2016-09-06 15 views
15

说我有我的代码结构是这样的:在这种情况下,在cpp文件中编写模板专门化可以吗?

  • 那么header1.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; 
    }; 
    
  • 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; 
    } 
    

我的前提是,我只在cpp文件中使用特定的专门化,所以我不必处理链接器问题。 我知道这将不适用于包括header1.hcpp2.cpp文件,并试图仅使用use_case<int>或重新定义违反ODRimplementation<int>。所以我问的是这个代码是否类似于它的linear form(一个版本,其中一切都被放入一个单一的CPP文件与一致的顺序),(显然)编译好。

+0

你可以使用'extern'模板来达到这个目的。 –

+0

@KerrekSB我被内联命名空间带走了。假设我没有C++ 11代码(如给出的)生病? –

+0

你在寻找什么额外的细节? – Barry

回答

8

是的,只要这只用于相同的翻译单元内,这是格式良好的。

请记住,#include的效果与引用文件逐字地插入到翻译单元中一样。

这就是#include

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

每一个C++翻译单元是一个单一的虚拟文件。

因此,一个格式良好的翻译单位中的每个专业化都会在定义它的同一翻译单元中引用。

Q.E.D.

0

一般来说,我同意@萨姆的答案,但我只会为本地类型做这样的专业化。对于“本地类型”,我的意思是仅在该翻译单元中可访问的类型,例如,一个仅在此.cpp文件中定义的类(在匿名名称空间中)。

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

所以int它绝对不是一个“本地”专业化的好人选。

如果你仍然想在.cpp文件中本地化专业化,也许你想添加一个额外的标签到模板参数(这也需要向原始模板添加另一个参数),这个标签将与一个本地类型(例如,在该文件中的匿名名称空间内定义struct private_tag{};并在专业化中使用它)。这样,专业化有一个独特的类型,不能在任何其他TU中使用,因此您可以安全地避免ODR违规。

相关问题