我正在尝试在构造函数上执行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时不能继承构造函数?没有第二个构造函数重载,一切正常。
答案 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。)