2013-06-04 111 views
7

我很努力地访问类模板中定义的静态成员函数。 在头文件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; 
} 

当我编译克TemplateTest.cpp ++它正确生成目标文件,但是当我尝试将其链接到驱动程序类它给我的链接错误“未定义引用到`TemplateTest :: invoke()“

我经历了其他相关的帖子,如this one,但我没有试图访问函数模板。

任何线索都非常感谢。

+4

将实现移动到头文件。模板的实现需要对所有使用它们的TU都可见。 –

回答

5

你是对的,你从TemplateTester.cpp创建对象文件将包含您所提供的专业化的象征。情况就是这样,因为任何明确的特殊化都会导致模板被实例化,而且这种情况更是如此,因为您甚至添加了显式实例化(实际上并不需要)。

但是,在编译driver.cpp时,编译器不知道专业化,因为您只包含TemplateTester.h,并且专业化在那里没有提及。所以编译器实例化了这个模板,当然没有使用专门的定义,所以你得到了你的问题。

标准说(由我斜体):

(§14.7。3/6)如果一个模板,一个成员模板或一个类模板的成员是明确专门化的,那么在该专业化的第一次使用之前,该专业化应该在每个翻译单元中进行隐式实例化,这种用途发生了;不需要诊断。如果程序没有提供显式专门化的定义,并且专门化的使用方式可能会导致隐式实例化或成员是虚拟成员函数,那么该程序不合格,不需要诊断。对于已声明但未定义的显式特化,永远不会生成隐式实例化。 [...]

因此,您需要同时制作编译器在driver.cpp上工作时已知的专用化的声明和定义。这样做的最好方法是将整个专业化添加到TemplateTester.h

再次请注意,显式实例化实际上并不需要。

+1

感谢您的解释@jogojapan。这实际上是我正在处理的模板静态库的原型。现在我明白了为什么它会失败我想我可以移动定义来保持编译器的快乐。 – jazaman

3

有几个问题:

  • 你不需要显式实例完全专用的模板
  • ,如果你想要把你静态方法在头部,然后用inline。否则,你会得到多个实例和链接器问题
  • 模板专业化,你放在标题中,并定义源文件中的方法
  • 如果你不想在模板中调用某些东西,你不需要定义它。你会得到编译器错误,这意味着更早发现错误。

// 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; 
} 
+0

Thanks @BЈовић我实际上试图在这里想出一个原型。可能是我应该明确地提到他们。类模板实际上是静态库的一部分,因此,我认为我仍然需要实例化。但你是对的,我不应该在课堂上定义函数。它应该在外面完成。我会试试看看它是否能解决我的问题。 – jazaman

+0

@jazaman不,你不需要实例化完全专用的模板,因为它们就像普通(非模板)类。如果你在几个地方包含你的头文件,你会得到链接器错误。 –

+0

在阅读了其他答案后,我明白,如果它是完全专业的情况下,不需要再做。 – jazaman