Question

I am struggling to access static member function defined inside class template. In the header file TemplateTest.h I defined the primary class Template as:

#include<iostream>

template<class T, class U>
struct TemplateTest
{
public:
    void static invoke();
    /*{

        std::cout << "Should not be called" << std::endl;

    }*/
};

Then Source File TemplateTester.cpp I put a specialization:

#include "TemplateTest.h"

template<>
struct TemplateTest<int, bool>
{
    static void invoke()
    {
        std::cout << "invoke<int, bool>" << std::endl;   
    }
};

template struct TemplateTest<int, bool>; //instantiate to resolve linker issue

I explicitly instantiated the class with so linker resolves correctly.

In the driver driver.cpp :

include "TemplateTest.h"

int main()
{
    TemplateTest<int, bool>::invoke();
    return 0;
}

When I compile the TemplateTest.cpp with g++ it generates the object file correctly but when I try to link it to the driver class it gives my linker error "undefined reference to `TemplateTest::invoke()"

I went through other related postings like this one but I am not trying access a function template.

Any clue is much appreciated.

Was it helpful?

Solution

You are right that the object file you create from TemplateTester.cpp will contain a symbol for the specialization you provided. This is the case because any explicit specialization causes the template to be instantiated, and it is doubly the case because you even added an explicit instantiation (which is actually unnecessary).

However, at the time when driver.cpp is compiled, the compiler does not know about the specialization, because you only include TemplateTester.h, and the specialization isn't mentioned there. So the compiler instantiates the template, of course not using the specialized definition, so you get your problem.

The Standard says (Italics by me):

(§14.7.3/6) If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required. If the program does not provide a definition for an explicit specialization and either the specialization is used in a way that would cause an implicit instantiation to take place or the member is a virtual member function, the program is ill-formed, no diagnostic required. An implicit instantiation is never generated for an explicit specialization that is declared but not defined. [...]

So you need to make both, the declaration and the definition of the specialization known to the compiler when it works on driver.cpp. The best way of doing this is by adding the entire specialization to TemplateTester.h.

Note, again, that an explicit instantiation is not actually required.

OTHER TIPS

There are several problems :

  • you do not need to explicitly instantiate fully specialized template
  • if you want to put your static method in the header, then use inline. Otherwise you will get multiple instances and linker problems
  • template specializations you put in the header, and define methods in the source files
  • if you do not want something to be called in a template, you don't need to define it. You'll get compiler errors, and that means catching errors earlier.

// TemplateTest.h
#include<iostream>

template<class T, class U>
struct TemplateTest;
template<>
struct TemplateTest<int, bool>
{
    inline static void invoke()
    {
        std::cout << "invoke<int, bool>" << std::endl;   
    }
};

// main.cpp
include "TemplateTest.h"

int main()
{
    TemplateTest<int, bool>::invoke();
}

Another way is to change the header, and add the source file.

// TemplateTest.h
#include<iostream>

template<class T, class U>
struct TemplateTest;

template<>
struct TemplateTest<int, bool>
{
    static void invoke();
};

// TemplateTest.cpp
#include "TemplateTest.h"
void TemplateTest<int, bool>::invoke()
{
  std::cout << "invoke<int, bool>" << std::endl;   
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top