7

我正在努力访问在类模板中定义的静态成员函数。在头文件 TemplateTest.h 中,我将主类 Template 定义为:

#include<iostream>

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

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

    }*/
};

然后 Source File 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 时,它会正确生成目标文件,但是当我尝试将其链接到驱动程序类时,它会给出我的链接器错误“未定义对 `TemplateTest::invoke() 的引用”

我浏览了其他类似的相关帖子,但我没有尝试访问功能模板。

任何线索都非常感谢。

4

2 回答 2

5

您是对的,您从中创建的目标文件TemplateTester.cpp将包含您提供的专业化的符号。之所以如此,是因为任何显式特化都会导致模板被实例化,而且情况更是如此,因为您甚至添加了显式实例化(这实际上是不必要的)。

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

标准说(我用斜体字):

(§14.7.3/6)如果模板、成员模板或类模板的成员被显式特化,则应在第一次使用该特化之前声明该特化,这将导致发生隐式实例化,在每个发生此类使用的翻译单元;不需要诊断。如果程序没有为显式特化提供定义,并且该特化的使用方式会导致发生隐式实例化,或者该成员是虚拟成员函数,则该程序是格式错误的,不需要诊断。永远不会为已声明但未定义的显式特化生成隐式实例化。[...]

所以你需要让编译器在工作时知道特化的声明和定义driver.cpp。最好的方法是将整个专业化添加到TemplateTester.h.

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

于 2013-06-04T05:16:58.850 回答
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;   
}
于 2013-06-04T05:07:03.880 回答