【问题标题】:specialize a template class constructor专门化一个模板类构造函数
【发布时间】:2015-03-12 16:04:33
【问题描述】:

我想专门化一个模板类构造函数:

如果类型是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 中。

但是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 错误?!

【问题讨论】:

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


【解决方案1】:

您的代码不正确。顶级 T 不能在 SFINAE 上下文中用于其方法,这是您正在尝试做的。只有在直接上下文中发生的替换可能导致演绎失败(第 14.8.2/8 节):

只有在函数类型及其模板参数类型的即时上下文中的无效类型和表达式会导致推演失败。 [注意:替换类型和表达式的评估可能会导致副作用,例如类模板特化和/或函数模板特化的实例化,隐式定义函数的生成等。此类副作用不在“立即上下文”,并可能导致程序格式错误。 ——尾注]

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)
{ }

【讨论】:

  • 当我必须使用该解决方法进行复制时,我建议添加一个静态断言来确认std::is_same&lt;_T,T&gt;,以保护您免受恶意用户明确提供不同类型的伤害。顺便说一句,_T 是保留的……
  • @galop1n 无需在此处查看is_same;构造函数模板参数不能显式提供。
猜你喜欢
  • 2016-07-02
  • 1970-01-01
  • 1970-01-01
  • 2019-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-13
  • 2015-07-05
相关资源
最近更新 更多