我正在努力访问类模板中定义的静态成员函数。 在头文件TemplateTest.h中,我将主类模板定义为:
#include<iostream>
template<class T, class U>
struct TemplateTest
{
public:
void static invoke();
/*{
std::cout << "Should not be called" << std::endl;
}*/
};
然后源文件TemplateTester.cpp我把专业化:
#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
我明确地实例化了这个类,因此链接器正确解析。
在驱动程序driver.cpp中:
include "TemplateTest.h"
int main()
{
TemplateTest<int, bool>::invoke();
return 0;
}
当我使用g ++编译TemplateTest.cpp时,它会正确生成目标文件,但是当我尝试将其链接到驱动程序类时,它会给出我的链接器错误&#34;未定义的对`TemplateTest :: invoke()&#的引用34;
我浏览了其他相关帖子,例如this one,但我没有尝试访问功能模板。
非常感谢任何线索。
答案 0 :(得分:5)
您是对的,您从TemplateTester.cpp
创建的目标文件将包含您提供的专业化的符号。这种情况就是这种情况,因为任何显式特化都会导致模板被实例化,并且情况更是如此,因为您甚至添加了一个显式实例化(实际上这是不必要的)。
但是,在编译driver.cpp
时,编译器不知道特化,因为您只包含TemplateTester.h
,并且那里没有提到特化。所以编译器实例化模板,当然不使用专门的定义,所以你得到了你的问题。
标准说(我用斜体字):
(§14.7.3/ 6)如果一个模板,一个成员模板或一个类模板的成员被明确专门化,那么该专门化应该在第一次使用该特化之前声明,这将导致隐式实例化发生,在发生此类使用的每个翻译单元中; 无需诊断。如果程序没有为显式特化提供定义,并且特殊化的使用方式会导致隐式实例化或成员是虚拟成员函数,则程序格式错误,无需诊断。永远不会为已声明但未定义的显式特化生成隐式实例化。 [...]
因此,当编译器在driver.cpp
上工作时,您需要同时创建编译器已知的声明和定义。最好的方法是将整个专业化添加到TemplateTester.h
。
再次注意,实际上并不需要显式实例化。
答案 1 :(得分:3)
有几个问题:
inline
。否则,您将获得多个实例和链接器问题</ li>
// 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();
}
另一种方法是更改标题,然后添加源文件。
// 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;
}