【问题标题】:Inlining Template Specialization内联模板专业化
【发布时间】:2019-01-29 22:17:45
【问题描述】:

如果我有一个包含在整个项目中的标头 foo.h,那么当它包含的只是以下内容时,它似乎可以正常工作:

template<typename T>
void foo(const T param) {
    cout << param << endl;
}

但是当我向 foo.h 添加规范时,我得到一个定义规则 (ODR) 错误:

template<>
void foo(const bool param) {
    cout << param << endl;
}

显然我可以通过inline'ing 专业化来解决这个问题。我的问题是,我为什么需要?如果模板不违反 ODR,为什么还要专门化?

【问题讨论】:

  • 如果定义了主体,模板函数的特化就是定义。
  • @NathanOliver 是的,我看过那个……它没有解决专业化问题。我真的只是希望官方说我必须inline。看起来像StoryTeller has got me
  • @JonathanMee 不是吗?在 tpl.h(取自 Explicit Specialization)下的答案中间呢: 具有完全相同的代码块?
  • @NathanOliver Heh... 看看那个。我只看了这个问题:/我不介意重复这个。因为那里回答得很好。你怎么看?

标签: c++ inline template-specialization one-definition-rule template-function


【解决方案1】:

显式特化不是隐式内联的。它必须显式地内联。

[temp.expl.spec]/12

函数或变量模板的显式特化是 仅当使用 inline 说明符声明或定义为 inline 时 删除,并且与它的函数或变量无关 模板是内联的。 [ 示例:

template<class T> void f(T) { /* ... */ }
template<class T> inline T g(T) { /* ... */ }

template<> inline void f<>(int) { /* ... */ }   // OK: inline
template<> int g<>(int) { /* ... */ }           // OK: not inline

 — 结束示例 ]

所以你必须这样做,因为标准说你必须这样做。

【讨论】:

    【解决方案2】:

    模板免于 ODR 的原因仅仅是没有其他选择。

    从编译器的角度来看,模板不是“有形的最终产品”。模板的实现必须随身携带,以便在使用时可以将其扩展为可编译的代码。结果,它必须驻留在头文件中,并且来自不同编译单元的重复定义是随之而来且不可避免的。由于这是不可避免的,因此该标准做出了妥协,将其免于 ODR。

    函数是可以很容易地编译成目标代码的最终产品,因此编译器讨厌看到潜在的冲突定义,即使完全可以比较代码并在代码相同的情况下继续进行。然而,编译器认为他们懒得做这样的额外检查,因此标准禁止了多个定义。

    现在,模板函数的 explicit/full 特化是 de facto 一个函数,而不是一个模板 - 因为所有缺失的部分都已被填充并且没有需要再携带专门功能的定义。相比之下,部分特化事实上是一个模板,因为它的实现仍然需要在编译期间进行。因此,部分模板特化享有从模板继承的豁免权,而显式/完全特化则没有。

    【讨论】:

    • 模板不能免除 ODR,令牌应该相同,生成的实例应该“行为”相同(ADL 的可见功能,...)。它只是不需要inline 关键字。
    猜你喜欢
    • 2020-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-28
    • 2015-08-01
    • 2011-09-23
    相关资源
    最近更新 更多