内部模板类的递归特化的结束

时间:2015-06-30 01:34:59

标签: c++ templates c++11 specialization

考虑这个有效的代码:

#include <typeinfo>

template <typename ...> struct A;

template <typename First, typename... Rest>
struct A<First, Rest...> {
    static void execute() {
        std::cout << typeid(First).name() << ' ';
        A<Rest...>::execute();
    }
};

template <>
struct A<> {
    static void execute() {}  // End of recursion.
};

int main() {
    A<char, bool, int>::execute();  // char bool int
}

那么为什么下面的递归结束不能编译(注释中提供的错误语句):

#include <typeinfo>

template <typename ...> struct A;

template <typename... Ts>
struct A {
    template <typename...> struct B;
    template <typename...> static void execute();
};

template <typename... Ts>
template <typename First, typename... Rest>
struct A<Ts...>::B<First, Rest...> {
    static void execute() {
        std::cout << typeid(First).name() << ' ';
        B<Rest...>::execute();
    }
};

template <typename... Ts>
template <> // invalid explicit specialization before '>' token
struct A<Ts...>::B<> {  // template parameters not used in partial specialization: Ts
    static void execute() {}  // End of recursion
};

template <typename... Ts>
template <typename... Us>
void A<Ts...>::execute() {
    B<Ts..., Us...>::execute();
}

int main() {
    A<char, bool, int>::execute<double, short, float>();
}

当我使用这个递归结束而不是上面时它确实有效:

template <typename... Ts>
template <typename Last>
struct A<Ts...>::B<Last> {
    static void execute() {std::cout << typeid(Last).name();}
};

但我只是想知道原始尝试的错误。此外,我必须使用第二种方式重复执行execute()函数的主体(这当然​​会导致更多的维护责任)。

GCC 4.9.2指出A<char, bool, int>::B<>是一种不完整的类型。但我定义了它。

1 个答案:

答案 0 :(得分:2)

[temp.expl.spec] / p15禁止显式专门化成员模板,而不明确专门化每个封闭模板:

  

成员或成员模板可以嵌套在许多封闭的类模板中。在对这样一个成员的显式特化中,成员声明前面应该有一个template<>,用于明确专门化的每个封闭类模板。 [例如:

template<class T1> class A {
    template<class T2> class B {
        void mf();
    };
};
template<> template<> class A<int>::B<double>;
template<> template<> void A<char>::B<char>::mf();
     

- 结束示例]

例如,此代码编译:

template <>
template <>
struct A<>::B<> {
    static void execute() {}  // End of recursion
};

但它不允许您使用封闭类模板中的模板参数。更好的方法是在主模板中使用包扩展“技巧”:

template <typename... Ts>
template <typename... Args>
struct A<Ts...>::B {
    static void execute() {
        using unpack = int[];
        (void)unpack{((std::cout << typeid(Args).name() << ' '), 0)...};
    }
};