本文记录在各平台(g++、msvc)中实测《C++模板元编程实战:一个深度学习框架的初步实现》中代码的过程。
1.3.2节,作者给出了这一段代码:
`
template
struct Wrapper
{
template
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
struct Fun_
{
constexpr static size_t value = 0;
};
};
template <>
struct Wrapper::Fun_
{
constexpr static size_t value = 1;
};
但是这要求
Wrapper是一个普通类而非模板类,当
Wrapper不能表示为普通类时,不能通过简单的办法通过编译,而必须使用书中后续给的代码:
template
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
struct Fun_<int, TDummy>
{
constexpr static size_t value = 1;
};
否则报错:default template arguments may not be used in partial specializations(在部分特化中不能使用默认模板参数)。 这个写法依赖于模板特化的规则,但是不允许在部分特化中使用默认模板参数是有道理的,考虑:
template
struct A{
};
template
struct A<int, U>
{
U value;
};
对于
A<int, double>`,特化选择陷入两难境地。直接禁止部分特化使用默认模板参数保持了一致性(可以认为部分特化的参数+默认参数优先级最高)。