C++ 在这种情况下,可以在cpp文件中写入模板专门化吗?

C++ 在这种情况下,可以在cpp文件中写入模板专门化吗?,c++,template-specialization,C++,Template Specialization,假设我的代码是这样构造的: 校长1.h template <class T, template<class> class C> struct metafunction { using type = typename C<T>::type; }; inline namespace msn { template <class T> struct implementation; } // uses the *implementa

假设我的代码是这样构造的:

  • 校长1.h

    template <class T, template<class> class C>
    struct metafunction {
        using type = typename C<T>::type; 
    };
    
    inline namespace msn {
        template <class T> struct implementation; 
    }
    
    // uses the *implementation* not defined in the header!
    template <class T>
    struct use_case {
        using type = typename metafunction<T, implementation>::type; 
    }; 
    
    模板
    结构元功能{
    使用type=typename C::type;
    };
    内联命名空间msn{
    模板结构实现;
    }
    //使用未在标题中定义的*实现*!
    模板
    结构用例{
    使用type=typename元函数::type;
    }; 
    
  • cpp1.cpp

    #include <header1.h>
    
    // I'll only need this in this compilation unit, so the
    // question is:    "Is this a good place to define it?"
    template <>
    struct implementation<int> {
        using type = int; 
    }; 
    
    int main() {
        using tt = int; 
        // is this point of instantiation OK due to 
        // the existence of a specialization in the same cpp file? 
        using tt = use_case<int>::type; 
    
        tt var; 
        (void)var; 
    }
    
    #包括
    //我只需要在这个编译单元中使用它,所以
    //问题是:“这是定义它的好地方吗?”
    模板
    结构实现{
    使用type=int;
    }; 
    int main(){
    使用tt=int;
    //由于以下原因,此实例化点是否正常
    //同一cpp文件中是否存在专门化?
    使用tt=用例::类型;
    tt-var;
    (无效)var;
    }
    

我的先决条件是,我将只在cpp文件中使用特定的专门化,这样我就不必处理链接器问题我知道这对
cpp2.cpp
文件不起作用,包括
header1.h
,并尝试只使用
用例
或重新定义违反ODR的
实现
。所以我要问的是,这段代码是否类似于它(一个版本,其中所有内容都以一致的顺序放入一个cpp文件中)编译得很好

是的,只要只在同一个翻译单元中使用,这是格式良好的

请记住,
#include
的效果就好像引用的文件被逐字插入翻译单元一样

这就是
#include
的含义

由此,我们可以得出几个结论:

<>每个C++翻译单元是一个虚拟文件。 因此,格式良好的翻译单元中的每个专门化都在定义它的同一翻译单元中引用


Q.E.D.

一般来说,我同意@Sam的答案,但我只会对本地类型进行专门化。“本地类型”指的是只能在这个翻译单元中访问的类型,例如,仅在这个.cpp文件中定义的类(在匿名名称空间中)

原因是,当以这种方式对一个可广泛访问的类型进行专门化时,比专门化更广泛,很容易出现ODR(一个定义规则)冲突。如果将来有其他代码开始使用相同类型的模板,很容易理解,您会得到两个不同的模板实例化(一个有专门化,一个没有专门化)。在这种情况下,这是一个ODR冲突,行为没有定义

所以
int
它绝对不是“本地”专业化的好候选


如果您仍然希望在.cpp文件中本地实现专门化,可能需要向模板参数添加一个额外的标记(这也需要向原始模板添加另一个参数),并且该标记将使用本地类型(例如定义
struct private_tag{};
在此文件中的匿名命名空间中,并在专用化中使用它)。这样,专门化有一个唯一的类型,不能在任何其他TU中使用,因此您可以避免ODR冲突。

您可以为此使用
extern
模板。@KerrekSB我被内联名称空间迷住了。假设我没有C++11,那么代码(如给定的)是否格式不正确?你在寻找什么额外的细节?比如“我在名称查找方面会有问题吗?”“实例化点是我的编译器需要所有信息的第一个地方”等等。基本上我想强化这个设计