如何在继承构造函数时执行适当的SFINAE?

时间:2014-11-09 23:35:51

标签: c++ c++11

我正在尝试在构造函数上执行SFINAE。我想为整数启用一个重载,为其他所有启用一个。我知道我可以创建一个base(int)base(T)构造函数,但我想这样做。

template <class T>
struct base
{
    template <class T1 = T>
    base(T1, typename std::enable_if<std::is_same<T1, int>::value>::type* = nullptr) {}

    template <class T1 = T>
    base(T1, typename std::enable_if<!std::is_same<T1, int>::value>::type* = nullptr) {}
};

然后我创建一个继承构造函数的主Base类:

template <class T>
struct Base : base<T>
{
    using base<T>::base;
};

但是当我使用任何Base实例化T时,我会收到以下错误:

source_file.cpp:21:15: error: call to deleted constructor of 'Base<int>'
    Base<int> v(4);
              ^ ~
source_file.cpp:16:25: note: deleted constructor was inherited here
    using base<T>::base;
                        ^
source_file.cpp:7:5: note: constructor cannot be inherited
    base(T1, typename std::enable_if<std::is_same<T1, int>::value>::type* = nullptr) {}
    ^

当我直接实例化base时,它可以毫无问题地工作。为什么我在做SFINAE时不能继承构造函数?没有第二个构造函数重载,一切正常。

2 个答案:

答案 0 :(得分:2)

通过在base中仅定义通用构造函数并为base<int>DEMO)提供特化,您可以在示例程序中完全避免此问题:

template <class T>
struct base
{
    base(T) { std::cout << "generic constructor\n"; }
};

template <>
base<int>::base(int) { std::cout << "int specialization\n"; }

或使用代码分派代替SFINAE(DEMO):

template <class T>
class base
{
    base(std::true_type, int) { std::cout << "int specialization\n"; }
    base(std::false_type, T) { std::cout << "generic constructor\n"; }

public:
    base(T t) : base(std::is_same<int, T>{}, std::move(t)) {}
};

答案 1 :(得分:0)

与构造函数的参数列表不同,整个模板参数列表始终是继承的,包括默认模板参数。将SFINAE放在那里:

template <class T>
struct base
{
    template <class T1 = T,
      typename std::enable_if<std::is_same<T1, int>::value>::type* = nullptr>
    base(T1) {}

    template <class T1 = T,
      typename std::enable_if<!std::is_same<T1, int>::value>::type* = nullptr>
    base(T1) {}
};

这适用于Clang和GCC,-std=c++11-std=c++1z模式。 (仅测试最新版本,分别为3.6和5.1。)