使用c ++特化模板时的奇怪行为

时间:2014-01-12 05:41:19

标签: c++ templates

我是使用c ++模板编程的新手。我有3个代码文件

的main.cpp

#include "template_test.h"
#include <iostream>

using namespace std;

int main()
{
    mytest<int> mt;
    mt.method(1);

    system("pause");

    return 0;
}

template_test.h

#include <iostream>
using namespace std;

template<class T>
class mytest
{
public:

    void method(T input){}
};


template<>
void mytest<int>::method(int input)
{
    cout << "ok" << endl;
}

template_test.cpp

#include "template_test.h"

//empty

该代码在VS2013中生效。但是,当我将代码更改为2个时,我的代码就出现了问题。

1.第一个是链接器错误代码。

的main.cpp

#include "template_test.h"
#include <iostream>

using namespace std;

int main()
{
    mytest<int> mt;
    mt.method(1);

    system("pause");

    return 0;
}

template_test.h

#include <iostream>
using namespace std;

template<class T>
class mytest
{
public:

    void method(T input);
};

template<class T>
void mytest<T>::method(T input)
{
    cout << " " << endl;
}//explicit specialization here

template<>
void mytest<int>::method(int input)
{
    cout << "ok" << endl;
}

template_test.cpp

#include "template_test.h"

//empty

2.第二个输出什么都没有,而不是正确答案'ok'。

的main.cpp

#include "template_test.h"
#include <iostream>

using namespace std;

int main()
{
    mytest<int> mt;
    mt.method(1);

    system("pause");

    return 0;
}

template_test.h

#include <iostream>
using namespace std;

template<class T>
class mytest
{
public:

    void method(T input){}
};

template_test.cpp

#include "template_test.h"

template<>
void mytest<int>::method(int input)
{
    cout << "ok" << endl;
}//move from .h to .cpp file here

c ++模板的奇怪行为让我感到困惑。那么,问题是什么?

2 个答案:

答案 0 :(得分:3)

第一个问题是由您的显式专业化

引起的
template<>
void mytest<int>::method(int input)
{
    cout << "ok" << endl;
}

在类定义之外的头文件中定义,没有关键字inline

显式特化会导致定义实际函数(而不仅仅是模板)。该定义将在每个翻译单元中出现,因此如果单独编译template_test.cppmain.cpp,则函数的定义将包含在两个目标文件中,从而在链接时导致多重定义错误(因为它违反了ODR,即单一定义规则。

最好通过在类模板定义中包含函数定义(通过专门化int的整个类模板)或使用关键字inline来避免这种情况:

template<>
inline void mytest<int>::method(int input)
{
    cout << "ok" << endl;
}

第二个问题是由于必须始终在使用模板专门化之前声明模板特化:

  

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

由于您的main.cpp包含头文件,而不包含.cpp文件,因此在main.cpp中使用模板特化时,不知道模板特化的声明。您可以通过在头文件中包含特殊化来解决这个问题,或者在类模板定义中(通过专门化int的整个类模板),或者在类模板定义之外使用关键字inline。 / p>

答案 1 :(得分:0)

你先问第二个问题。使用模板时请记住规则。不要将模板实现与cpp文件分开。将它们全部放在一个.h文件中。

你的第一个代码编译好我的VC2012,我不确定VC2013有什么问题。