我有以下模板化对象:
template< typename type_1, typename type_2 > struct result
{
// I want to enable these two constructors only if type_1 != type_2
result( type_1 f ) : foo{f} {}
result( type_2 b ) : bar{b} {}
// I want to enable this constructor only if type_1 == type_2
result( type_1 f, type_2 b ) : foo{f}, bar{b} {}
// Other member functions removed.
type_1 foo;
type_2 bar;
};
如何根据需要使用std::enable_if
启用或禁用构造函数?
e.g:
这个只有前两个构造函数:
result<string,int> // type_1 != type_2
这个只有第三个构造函数:
result<int,int> // type_1 == type_2
答案 0 :(得分:5)
This似乎有效,但我不确定这是最佳方式
因此,只需将具有默认值的新模板参数添加到构造函数中以启用SFINAE
#include <type_traits>
template< typename type_1, typename type_2 >
struct result
{
// I want to enable these two constructors only if type_1 != type_2
template<typename T1 = type_1, typename T2 = type_2>
result( type_1 f,
typename std::enable_if<!std::is_same<T1, T2>::value>::type * = nullptr )
: foo{f} {}
template<typename T1 = type_1, typename T2 = type_2>
result( type_2 b,
typename std::enable_if<!std::is_same<T1, T2>::value, int >::type * = nullptr )
: bar{b} {} /* ^^^ need this to avoid duplicated signature error with above one*/
// I want to enable this constructor only if type_1 == type_2
template<typename T1 = type_1, typename T2 = type_2>
result( type_1 f, type_2 b,
typename std::enable_if<std::is_same<T1, T2>::value>::type * = nullptr )
: foo{f}, bar{b} {}
type_1 foo;
type_2 bar;
};
int main()
{
result<int, double> r(1);
result<int, double> r2(1.0);
result<int, int> r3(1, 2);
// disbaled
//result<int, double> r4(1, 2.0);
//result<int, int> r5(1);
}
答案 1 :(得分:4)
主模板可以作为不匹配类型的专门化。对于匹配类型,您可以部分专门化:
template <typename type_1, typename type_2>
struct result
{
result( type_1 f ) : foo{f} {}
result( type_2 b ) : bar{b} {}
type_1 foo;
type_2 bar;
};
template <typename type>
struct result<type, type>
{
result( type f, type b ) : foo{f}, bar{b} {}
type foo;
type bar;
};
答案 2 :(得分:3)
这类似于@BryanChen的答案,但更清晰的IMO :)您可以使用继承来改善歧义解决方案并将enable_if
移动到构造函数的模板参数。
#include <iostream>
#include <string>
#include <type_traits>
using namespace std;
template <int N>
class Disambiguator;
template<>
class Disambiguator<0>{};
template <int N>
class Disambiguator : public Disambiguator<N-1>{};
using Disambiguate = Disambiguator<100>;
template< typename type_1, typename type_2 > struct result
{
template <typename T, typename U>
using IsSame = typename enable_if<is_same<T, U>::value>::type;
template <typename T, typename U>
using IsNotSame = typename enable_if<!is_same<T, U>::value>::type;
template <typename T = type_1, typename U = type_2, typename = IsNotSame<T,U>>
result( type_1 f, Disambiguator<0>) : foo{f} {cout<<"NotSameType"<<endl;}
template <typename T = type_1, typename U = type_2, typename = IsNotSame<T,U>>
result( type_2 b, Disambiguator<1>) : bar{b} {cout<<"NotSameType"<<endl;}
// I want to enable this constructor only if type_1 == type_2
template <typename T = type_1, typename U = type_2, typename = IsSame<T,U>>
result( type_1 f, type_2 b ) : foo{f}, bar{b} {cout<<"SameType"<<endl;}
// Other member functions removed.
type_1 foo;
type_2 bar;
};
int main()
{
result<float, int> c(1.0, Disambiguate{});
result<float, int> i(0, Disambiguate{});
result<int, int> j(0, 0);
result<string, int> s("abc", Disambiguate{});
result<string, int> si(0, Disambiguate{});
return 0;
}
编辑:您可以阅读@ Xeo的重载决议提示here。这就是我在上面的代码中使用的内容。
答案 3 :(得分:0)
另一种解决方案(与How do I use std::enable_if to enable or disable constructors depending on template types?更为相关,但仍然涉及禁用构造函数的问题)是使用默认为true的布尔模板参数:
template <class T, class Unreleated>
class MyClass {
public:
// Enable constructor if IsEnabled == True and T != int
template <bool IsEnabled = true,
typename std::enable_if<(IsEnabled && !std::is_same<T, int>::value),
int>::type = 0>
MyClass(T x) {
cout << "IsNotInt" << endl;
}
MyClass(int x) {
cout << "IsInt" << endl;
}
};
由于IsEnabled
的默认值为true,因此即使在构造函数中未使用模板参数,也将检查std::enable_if
条件。这也使您可以基于类的模板参数的值来启用/禁用构造函数:
template <int N, class Unreleated>
class MyOtherClass {
public:
// Enable constructor if IsEnabled == True and N > 0
template <bool IsEnabled = true,
typename std::enable_if<(IsEnabled && N > 0), int>::type = 0>
MyOtherClass(int x) {
cout << "N > 0" << endl;
}
// Enable constructor if IsEnabled == True and N <= 0
template <bool IsEnabled = true,
typename std::enable_if<(IsEnabled && N <= 0), int>::type = 0>
MyOtherClass(int x) {
cout << "N <= 0" << endl;
}
};