专门化模板 class 构造函数
specialize a template class constructor
我想特化一个模板class构造函数:
如果类型是 int 默认值是 50 和 -50。如果它是浮动默认值应该是 0.5 和 -0.5 .
我的代码是:
#include <iostream>
#include <limits>
#include <type_traits>
template<typename T>
class Foo{
public:
template<typename = typename std::enable_if<
std::is_integral<T>::value&& !std::is_floating_point<T>::value>::type>
Foo(T value1 = 50, T value2 = -50) :value1_(value1), value2_(value2){}
template<typename = typename std::enable_if<
std::is_floating_point<T>::value>::type>
Foo(T value1 = 0.5, T value2 = -0.5, void* dummy = 0) : value1_(value1), value2_(value2){}
T value1_, value2_;
};
int main()
{
Foo<float> test;
std::cout << test.value1_ << " " << test.value2_ << '\n';
Foo<int> test2;
std::cout << test2.value1_ << " " << test2.value2_;
}
它 works just fine 在 visual studio 2013 年。
main.cpp: In instantiation of 'class Foo<float>':
main.cpp:29:13: required from here
main.cpp:19:3: error: no type named 'type' in 'struct std::enable_if<false, void>'
Foo(T value1 = 50, T value2 = -50) :value1_(value1), value2_(value2){}
^
main.cpp: In instantiation of 'class Foo<int>':
main.cpp:32:11: required from here
main.cpp:23:3: error: no type named 'type' in 'struct std::enable_if<false, void>'
Foo(T value1 = 0.5, T value2 = -0.5, void* dummy = 0) : value1_(value1), value2_(value2){}
^
我的代码有错吗?如果是这样,为什么 visual studio 编译它?或者可能是 gcc 错误?!
您的代码不正确。顶级 T
不能在 SFINAE 上下文中用于其方法,这正是您正在尝试做的。只有在直接上下文中发生的替换才可能导致演绎失败 (§14.8.2/8):
Only invalid types and expressions in the immediate context of the function type and its template parameter types can result in a deduction failure. [ Note: The evaluation of the substituted types and expressions can result in side effects such as the instantiation of class template specializations and/or function template specializations, the generation of implicitly-defined functions, etc. Such side effects are not in the “immediate context” and can result in the program being ill-formed. — end note ]
GCC 和 Clang 拒绝您的代码是正确的。
一种解决方法是引入默认为顶级 T
的虚拟模板类型,并在 上引入 SFINAE。像这样:
template <typename T_ = T, // now the subsequent line *is* in
// an immediate context
typename = typename std::enable_if <
std::is_integral<T_>::value&& !std::is_floating_point<T_>::value
>::type>
Foo(T value1 = 50, T value2 = -50)
:value1_(value1), value2_(value2) { }
注意is_integral
和is_floating_point
是互斥的,你只需要检查其中一个。
在这个例子中,将默认值外包给另一个结构可能会简单得多,这样您就可以只有一个构造函数,如下所示:
Foo(T value1 = FooDefaults<T>::value1, T value2 = FooDefaults<T>::value2)
: value1_(value1), value2_(value2)
{ }
我想特化一个模板class构造函数:
如果类型是 int 默认值是 50 和 -50。如果它是浮动默认值应该是 0.5 和 -0.5 .
我的代码是:
#include <iostream>
#include <limits>
#include <type_traits>
template<typename T>
class Foo{
public:
template<typename = typename std::enable_if<
std::is_integral<T>::value&& !std::is_floating_point<T>::value>::type>
Foo(T value1 = 50, T value2 = -50) :value1_(value1), value2_(value2){}
template<typename = typename std::enable_if<
std::is_floating_point<T>::value>::type>
Foo(T value1 = 0.5, T value2 = -0.5, void* dummy = 0) : value1_(value1), value2_(value2){}
T value1_, value2_;
};
int main()
{
Foo<float> test;
std::cout << test.value1_ << " " << test.value2_ << '\n';
Foo<int> test2;
std::cout << test2.value1_ << " " << test2.value2_;
}
它 works just fine 在 visual studio 2013 年。
main.cpp: In instantiation of 'class Foo<float>':
main.cpp:29:13: required from here
main.cpp:19:3: error: no type named 'type' in 'struct std::enable_if<false, void>'
Foo(T value1 = 50, T value2 = -50) :value1_(value1), value2_(value2){}
^
main.cpp: In instantiation of 'class Foo<int>':
main.cpp:32:11: required from here
main.cpp:23:3: error: no type named 'type' in 'struct std::enable_if<false, void>'
Foo(T value1 = 0.5, T value2 = -0.5, void* dummy = 0) : value1_(value1), value2_(value2){}
^
我的代码有错吗?如果是这样,为什么 visual studio 编译它?或者可能是 gcc 错误?!
您的代码不正确。顶级 T
不能在 SFINAE 上下文中用于其方法,这正是您正在尝试做的。只有在直接上下文中发生的替换才可能导致演绎失败 (§14.8.2/8):
Only invalid types and expressions in the immediate context of the function type and its template parameter types can result in a deduction failure. [ Note: The evaluation of the substituted types and expressions can result in side effects such as the instantiation of class template specializations and/or function template specializations, the generation of implicitly-defined functions, etc. Such side effects are not in the “immediate context” and can result in the program being ill-formed. — end note ]
GCC 和 Clang 拒绝您的代码是正确的。
一种解决方法是引入默认为顶级 T
的虚拟模板类型,并在 上引入 SFINAE。像这样:
template <typename T_ = T, // now the subsequent line *is* in
// an immediate context
typename = typename std::enable_if <
std::is_integral<T_>::value&& !std::is_floating_point<T_>::value
>::type>
Foo(T value1 = 50, T value2 = -50)
:value1_(value1), value2_(value2) { }
注意is_integral
和is_floating_point
是互斥的,你只需要检查其中一个。
在这个例子中,将默认值外包给另一个结构可能会简单得多,这样您就可以只有一个构造函数,如下所示:
Foo(T value1 = FooDefaults<T>::value1, T value2 = FooDefaults<T>::value2)
: value1_(value1), value2_(value2)
{ }