【问题标题】:Class template member specialization类模板成员特化
【发布时间】:2014-03-22 17:54:14
【问题描述】:

我正在专门研究头文件中模板类的成员函数,如下所示:

#pragma once

#include <iostream>

template<class T>
struct Test
{
    void Print() { }
};

template<>
void Test<int>::Print()
{
    std::cout << "int" << std::endl;
}

将特化放在头文件中是否正确(没有内联),还是应该放在 cpp 文件中?如上所示,它编译得很好(使用 VS2012),但我很惊讶我没有收到多个定义链接器错误。

【问题讨论】:

  • 如果我将此代码包含在两个不同的文件中并实际使用 Test&lt;int&gt;::Print(使用 g++4.8.1),我确实会收到链接器错误。
  • VS2013 中没有链接器错误。 (甚至没有警告或任何东西,即使两个定义不同。)

标签: c++ specialization class-template


【解决方案1】:

ODR 需要对 ODR 使用的非内联函数有一个确切的定义(对于函数来说,这粗略意味着可能被调用)。

引用 n3485,[basic.def.odr]

4 每个程序都应包含一个定义 odr 中使用的每个非内联函数或变量 程序;无需诊断。

然后,模板有一个例外(即不是函数):

6 类类型[...]、类模板、非静态函数模板、静态数据成员可以有多个定义 类模板的类模板的成员函数或模板特化 某些模板参数没有在程序中指定,前提是[...]

[强调我的]

模板的显式特化不是模板。例如,显式专门化的类模板是一个类(具有奇怪的名称)。因此,您的假设是正确的,并且对明确专门化的类模板成员的多个定义违反了 ODR。

使用 g++4.8.1,我什至在这样的程序中遇到链接器错误;请注意,我使用了 ODR 功能。违反 ODR 无需诊断。

【讨论】:

    【解决方案2】:

    将专业化放在头文件中是规范形式(如boost 所做的那样),它不违反ODR。

    【讨论】:

    • 你能提供一个例子来说明 boost 是在哪里做的吗?我想知道,据我所知,ODR 对“未指定某些模板参数”的模板特化有明确的例外,但对于显式(=完整)特化却没有。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-30
    • 2012-04-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多