Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Initialize a template class private static variable in C++

I’m trying to compile a sample program in C++ using templates. The template class has a priavte static member variable which seems to be undefined when trying to compile. Going through other answers on SO, I realized that this variable needs to be defined as well. However my attempts at defining this variable have been unsuccessful so far, likely due to my lack of experience working with templates. Here is my sample program:

#include <iostream>
#include <array>

enum FRUIT
{
    APPLE,
    ORANGE
};

using FunctionPtr = void(*)(void);

template <FRUIT T>
void FruitFunction(void);

template <FRUIT...TotalFruits>
class TestClass
{
public:

    struct fruitGroup
    {
        FRUIT fruit;
        FunctionPtr func;
    };

    static int find_fruit(FRUIT fruit, int arg)
    {
        for (auto i = pv_mem_.begin(); i != pv_mem_.end(); ++i) {
            if (i->fruit == fruit) {
                break;
            }
        }

        return 0;
    }

private:
    constexpr static std::array<fruitGroup, sizeof...(TotalFruits)> pv_mem_ 
    {
        fruitGroup{TotalFruits, &FruitFunction<TotalFruits>}...
    };
};

int main()
{
    TestClass<FRUIT::APPLE, FRUIT::ORANGE> test;
    test.find_fruit(FRUIT::APPLE, 0);

    return 0;
}

This yields:

$ g++ -std=c++11 fruit.cpp -o foo
/tmp/ccqaSBYm.o: In function `TestClass<(FRUIT)0, (FRUIT)1>::find_fruit(FRUIT, int)':
fruit.cpp:(.text._ZN9TestClassIJL5FRUIT0ELS0_1EEE10find_fruitES0_i[_ZN9TestClassIJL5FRUIT0ELS0_1EEE10find_fruitES0_i]+0xf): undefined reference to `TestClass<(FRUIT)0, (FRUIT)1>::pv_mem_'
fruit.cpp:(.text._ZN9TestClassIJL5FRUIT0ELS0_1EEE10find_fruitES0_i[_ZN9TestClassIJL5FRUIT0ELS0_1EEE10find_fruitES0_i]+0x1d): undefined reference to `TestClass<(FRUIT)0, (FRUIT)1>::pv_mem_'
collect2: error: ld returned 1 exit status

I have tried defining pv_mem_ as:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

constexpr static std::array<TestClass::fruitGroup, sizeof...(TotalFruits)> pv_mem_;

but that resulted in the following error:

$ g++ -std=c++11 fruit.cpp -o foo
fruit.cpp:44:74: error: wrong number of template arguments (1, should be 2)
 constexpr static std::array<TestClass::fruitGroup, sizeof...(TotalFruits)> pv_mem_;
                                                                          ^
In file included from fruit.cpp:2:0:
/usr/include/c++/5/array:89:12: note: provided for ‘template<class _Tp, long unsigned int _Nm> struct std::array’
     struct array
            ^
fruit.cpp:44:76: error: uninitialized const ‘pv_mem_’ [-fpermissive]
 constexpr static std::array<TestClass::fruitGroup, sizeof...(TotalFruits)> pv_mem_;
                                                                            ^

What would be the right way to initialize this variable?

>Solution :

pv_mem_ is defined as follows

constexpr static std::array<fruitGroup, sizeof...(TotalFruits)> pv_mem_ 
{
  fruitGroup{TotalFruits, &FruitFunction<TotalFruits>}...
};

which uses & to take the address of FruitFunction<TotalFruits>, but since FruitFunction is only declared and not defined, it will generate an undefined reference error at runtime.

Adding the definition for the template function FruitFunction will solve the problem in C++17

template <FRUIT T>
void FruitFunction() { /* */ }

In C++11, constexpr static member variables still need to be defined outside the class, so you also need to add

template <FRUIT...TotalFruits>
constexpr std::array<
  typename TestClass<TotalFruits...>::fruitGroup, 
  sizeof...(TotalFruits)> TestClass<TotalFruits...>::pv_mem_;

Demo

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading