C++模板元编程 实测

本文记录在各平台(g++、msvc)中实测《C++模板元编程实战:一个深度学习框架的初步实现》中代码的过程。

1.3.2节,作者给出了这一段代码:

template <typename TW>
struct Wrapper
{
    template <typename T>
    struct Fun_
    {
        constexpr static size_t value = 0;
    };

    template <>
    struct Fun_<int>
    {
        constexpr static size_t value = 1;
    };
};

作者表示:在非完全特化的类模板中引入完全特化的分支代码是非法的。经过实测,该段代码在MSVC中可以不报错,在g++中报错。原因是:在MSVC中,编译器允许在类作用域内进行显式模板特化,而这在标准C++中是不符合规范的。
要使之可以在g++中通过编译,可以修改为:

struct Wrapper
{
    template <typename T>
    struct Fun_
    {
        constexpr static size_t value = 0;
    };
};

template <>
struct Wrapper::Fun_<int>
{
    constexpr static size_t value = 1;
};

但是这要求Wrapper是一个普通类而非模板类,当Wrapper不能表示为普通类时,不能通过简单的办法通过编译,而必须使用书中后续给的代码:

template <typename TW>
struct Wrapper
{
    TW value;

    template <typename T, typename TDummy = void>
    struct Fun_
    {
        constexpr static size_t value = 0;
    };

    template <typename TDummy>
    struct Fun_<int, TDummy>
    {
        constexpr static size_t value = 1;
    };
};

注意,我们不能使用

template <typename TDummy = void>
struct Fun_<int, TDummy>
{
    constexpr static size_t value = 1;
};

否则报错:default template arguments may not be used in partial specializations(在部分特化中不能使用默认模板参数)。
这个写法依赖于模板特化的规则,但是不允许在部分特化中使用默认模板参数是有道理的,考虑:

template <typename T = int, typename U = double>
struct A{

};

template <typename U = double>
struct A<int, U>
{
    U value;
};

对于A<int, double>,特化选择陷入两难境地。直接禁止部分特化使用默认模板参数保持了一致性(可以认为部分特化的参数+默认参数优先级最高)。

posted @ 2024-11-03 11:30  爱尔奎特你带我走吧  阅读(44)  评论(0)    收藏  举报