【问题标题】:Template specialization ambiguity: either specialized or original method may be linked模板专业化歧义:可以链接专业化或原始方法
【发布时间】:2017-07-06 23:44:21
【问题描述】:

查看 tps.hpp 中的base::m_visible 方法(它是«默认»):

#include <sstream>
#include <iostream>

template <typename T> struct base
{
  void m_log() const;
  void m_visible() const;
};

struct inheritor: base<inheritor>
{
  void log() const;
};

template <typename T> void base<T>::m_log() const
{
  std::ostringstream os;
  m_visible();
  os.str(""); // We have «default/default» if comment here, :-0
  std::cout << os.str();
}

template <typename T> void base<T>::m_visible() const
{
  std::cout
    << "default" << std::endl
  ;
}

专门用于 tps_spec.cpp 中的 inheritor 结构(命名为 «spec»):

#include "tps.hpp"

template <> void base<inheritor>::m_visible() const
{
  std::cout
    << "spec" << std::endl
  ;
}

void inheritor::log() const
{
  m_log();
}

并进一步从 tps_main.cpp 调用:

#include "tps.hpp"

int main(int, char **argv)
{
  std::cout << argv[0] << ": ";
  inheritor().m_log(); // We have «spec/spec» if call inheritor::log
  return 0;
}

结果取决于编译单元的顺序(GCC 4.8.4):

g++ -Wall -O3 -o tps1 tps_spec.cpp tps_main.cpp && g++ -Wall -O3 -o tps2 tps_main.cpp tps_spec.cpp && ./tps1 ; ./tps2
./tps1: spec
./tps2: default

只有在优化-O3 时才会发生这种情况。任何由 cmets 标记的实验版本都会产生不同的结果。 为什么?

【问题讨论】:

    标签: c++ templates specialization gcc4


    【解决方案1】:

    因为这是未定义的行为。

    如果一个模板是特化的,那么这个特化必须在任何地方都是“可见的”。

    您在一个翻译单元中声明和实施专业化。基本上,该专用模板声明完全位于该翻译单元的内部,并且该专门化仅对该翻译单元可见。您的tps_main 翻译单元没有模板专业化的可见性,也没有任何知识;因此,将其与具有此模板特化可见的不同翻译单元链接在一起会导致未定义的行为。

    您需要在头文件中声明并定义(这里有一些不太相关的例外)特化,以便每个包含头文件的翻译单元具有模板定义的文件也将具有专业化的定义。

    模板特化不是特定模板实例的某种模板的“实现”。模板特化基本上是一个完全独立的类声明。因此,如果您有一个使用该类的翻译单元,则必须声明该类。

    您不能只在一个翻译单元中声明一个类,并期望在另一个翻译单元中使用它而不让其他翻译单元看到该声明。

    基本上,您链接在一起的所有翻译单元都必须具有相同的类、对象和模板声明。这包括模板特化。

    这只是C++ templates can only be portably defined in header files的一种迂回说法。

    【讨论】:

    • 不,您需要在任何地方声明特化,但只要有一个定义(和实例化)就可以做到这一点。对无穷无尽的冗余定义进行过度、浪费的重新编译是最方便的。
    • 所以,在 tps.hpp 的底部附加声明 template &lt;&gt; void base&lt;inheritor&gt;::m_visible() const; 是问题的决定
    猜你喜欢
    • 1970-01-01
    • 2017-04-14
    • 1970-01-01
    • 2020-07-18
    • 2011-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多