代码之家  ›  专栏  ›  技术社区  ›  dyomas

模板专门化歧义:可以链接专门化方法或原始方法

  •  1
  • dyomas  · 技术社区  · 7 年前

    base::m_visible 中的方法 tps.hpp (默认设置):

    #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
      ;
    }
    

    inheritor 结构输入 tps_规范cpp

    #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 为什么?

    1 回复  |  直到 7 年前
        1
  •  2
  •   Sam Varshavchik    7 年前

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

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

    并定义 (除了一些不太相关的例外情况)头文件中的专门化,因此每个包含具有模板定义的头文件的翻译单元也将具有专门化的定义。

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

    C++ templates can only be portably defined in header files