c++ - 专门化模板类构造函数

标签 c++ class templates c++11 sfinae

我想特化一个模板类构造器:

如果类型是 int,默认值是 50-50。如果它是 float 的,默认值应该是 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 中。

但是gcc 4.9.2 rejects it :

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_integralis_floating_point 是互斥的,您只需检查其中一个即可。

在这个例子中,将默认值外包给另一个结构可能会简单得多,这样你就可以只有一个构造函数,如下所示:

Foo(T value1 = FooDefaults<T>::value1, T value2 = FooDefaults<T>::value2)
: value1_(value1), value2_(value2)
{ }

关于c++ - 专门化模板类构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27943503/

相关文章:

C++ 代码在 Win 2000 中崩溃但在 Win xp 中不崩溃

java - 迭代列表中的特定实例

c++ - 如何基于循环迭代器选择函数

c++ - 使用模板定义 bitset 的大小

c++ - 将 typename 与 reinterpret_cast() 结合使用

c++ - 是否有任何现有库在 C/CPP/Obj-C 中实现了 matlab 函数?

c++ - inline 或 constexpr 函数的多个定义的含义

class - ":"在 dart 的类构造函数中意味着什么?

c++ - 模板类成员 VS 嵌套类前向声明

c++ - GCC 模板参数推导/替换失败