C++-在模板类之外但在头中定义成员函数



我定义了一个带有一个成员函数的简单类模板。它是在类外定义的,具有额外的(显式)专门化,也在类外进行定义。一个头文件。如果在多个翻译单元中包含此标头,则会由于"一个定义规则"而导致链接器错误。

// Header with a template
template <class T>
class TestClass
{
public:
    TestClass() {};
    ~TestClass() {};
    bool MemberFunction();
};
template <class T>
bool TestClass<T>::MemberFunction()
{
    return true;
}
template <>
bool TestClass<double>::MemberFunction()
{
    return true;
};

到目前为止一切都很好。但是,如果我把成员函数的定义放在类主体中,链接器错误就会消失,函数可以在不同的翻译单元中使用。

// Header with a template
template <class T>
class TestClass
{
public:
    TestClass() {};
    ~TestClass() {};
    bool MemberFunction()
    {
        return true;
    }
};
template <>
bool TestClass<double>::MemberFunction()
{
    return true;
};

我的问题是为什么它会这样工作?我使用MSVC 2012。ODR在模板上有一些例外,这是我最初认为的原因。但是类内部/外部的"Base"函数的定义在这里起了作用。

14.7/5表示

5对于给定的模板和给定的模板参数集,

  • 显式实例化定义应在程序中最多出现一次
  • 一个程序中应最多定义一次显式专业化(根据3.2),以及
  • 显式实例化和显式专门化的声明都不应出现在程序中,除非显式实例化遵循显式专门化的声明

一个不需要实现来诊断违反此规则的情况。

第二个要点适用于您的案例。3.2中定义的ODR说明了同样的事情,尽管是以较少蒸馏的形式

无论在何处以及如何定义成员函数的非专用版本,专用版本定义

template <> bool TestClass<double>::MemberFunction()
{
    return true;
};

必须进入.cpp文件。如果保留在头文件中,一旦头包含在多个翻译单元中,就会产生ODR冲突。GCC可靠地检测到该违规行为。MSVC在这方面似乎不那么可靠。但是,正如上面引用的那样,不需要实现来诊断违反此规则的情况。

头文件应该只包含该专门化的非定义声明

template <> bool TestClass<double>::MemberFunction();

在MSVC中,错误的出现或消失取决于看似无关的因素,比如函数的非专用版本是如何定义的,这一定是MSVC编译器的一个怪癖。


经过进一步的研究,似乎MSVC的实现实际上已经被打破了:它的行为超出了";不需要诊断";语言规范给出的权限。

您在实验中观察到的行为与以下内容一致:将主函数模板声明为inline会自动使该模板的显式专用化inline。这不应该是那样的。14.7.3/14中的语言规范显示

函数模板的显式专用化只有在使用内联说明符声明或定义为已删除,并且独立于其函数模板是否内联。

相关内容

  • 没有找到相关文章

最新更新