如何有条件地显式应用默认构造函数?
How can I apply make a default constructor conditionally explicit?
问题
假设我们有一个(虚构的)class 模板 C<T>
带有条件显式默认构造函数。当且仅当 std::is_same_v<T, int>
时,默认构造函数应该是显式的。
A search on "[c++] conditionally explicit" returns this result: .
一个失败的解决方案
接受的答案给出了一个例子:
struct S {
template <typename T,
typename std::enable_if<std::is_integral<T>::value, bool>::type = false >
S(T) {}
template <typename T,
typename std::enable_if<!std::is_integral<T>::value, bool>::type = false>
explicit S(T) {}
};
稍微修改示例给出了此实现,它使用熟悉的方法 std::enable_if
:
template <class T>
class C {
public:
template <std::enable_if_t<std::is_same_v<T, int>, int> = 0>
C() {}
template <std::enable_if_t<!std::is_same_v<T, int>, int> = 0>
explicit C() {}
};
不幸的是,这甚至无法编译:demo
prog.cc: In instantiation of 'class C<int>':
prog.cc:15:10: required from here
prog.cc:10:12: error: no type named 'type' in 'struct std::enable_if<false, int>'
10 | explicit C() {}
| ^
prog.cc: In instantiation of 'class C<double>':
prog.cc:18:13: required from here
prog.cc:7:3: error: no type named 'type' in 'struct std::enable_if<false, int>'
7 | C() {}
| ^
问题似乎是构造函数的模板参数遗漏,禁用SFINAE引起的。
问题
- 为什么不能编译?
- 可能的实施方式是什么?
如果可能,我想避免专门化 class。
- What is a possible implementation?
你试过
template <class T>
class C {
public: // VVVVVVVVVVVVVV .................................V U here, not T
template <typename U = T, std::enable_if_t<std::is_same_v<U, int>, int> = 0>
C() {}
template <typename U = T, std::enable_if_t<!std::is_same_v<U, int>, int> = 0>
explicit C() {}
};
?
- Why does this not compile?
问题是 SFINAE 在 class 方法上使用方法本身的模板参数。
在原来的工作代码中:
template <typename T,
typename std::enable_if<std::is_integral<T>::value, bool>::type = false >
S(T) {}
其中 T
是特定于构造函数的模板参数(从单个参数推导出)。
相反,在你失败的代码中,
template <std::enable_if_t<std::is_same_v<T, int>, int> = 0>
C() {}
构造函数正在计算 class (T
) 的模板参数,而不是方法的模板参数。
使用技巧 typename U = T
,您将 class 的模板参数 T
转换为 U
方法的模板参数(您的构造函数案例,但也适用于其他方法)所以 std::enable_if_t
,根据 U
的测试,能够 enable/disable 构造函数。
问题
假设我们有一个(虚构的)class 模板 C<T>
带有条件显式默认构造函数。当且仅当 std::is_same_v<T, int>
时,默认构造函数应该是显式的。
A search on "[c++] conditionally explicit" returns this result:
一个失败的解决方案
接受的答案给出了一个例子:
struct S { template <typename T, typename std::enable_if<std::is_integral<T>::value, bool>::type = false > S(T) {} template <typename T, typename std::enable_if<!std::is_integral<T>::value, bool>::type = false> explicit S(T) {} };
稍微修改示例给出了此实现,它使用熟悉的方法 std::enable_if
:
template <class T>
class C {
public:
template <std::enable_if_t<std::is_same_v<T, int>, int> = 0>
C() {}
template <std::enable_if_t<!std::is_same_v<T, int>, int> = 0>
explicit C() {}
};
不幸的是,这甚至无法编译:demo
prog.cc: In instantiation of 'class C<int>':
prog.cc:15:10: required from here
prog.cc:10:12: error: no type named 'type' in 'struct std::enable_if<false, int>'
10 | explicit C() {}
| ^
prog.cc: In instantiation of 'class C<double>':
prog.cc:18:13: required from here
prog.cc:7:3: error: no type named 'type' in 'struct std::enable_if<false, int>'
7 | C() {}
| ^
问题似乎是构造函数的模板参数遗漏,禁用SFINAE引起的。
问题
- 为什么不能编译?
- 可能的实施方式是什么?
如果可能,我想避免专门化 class。
- What is a possible implementation?
你试过
template <class T>
class C {
public: // VVVVVVVVVVVVVV .................................V U here, not T
template <typename U = T, std::enable_if_t<std::is_same_v<U, int>, int> = 0>
C() {}
template <typename U = T, std::enable_if_t<!std::is_same_v<U, int>, int> = 0>
explicit C() {}
};
?
- Why does this not compile?
问题是 SFINAE 在 class 方法上使用方法本身的模板参数。
在原来的工作代码中:
template <typename T,
typename std::enable_if<std::is_integral<T>::value, bool>::type = false >
S(T) {}
其中 T
是特定于构造函数的模板参数(从单个参数推导出)。
相反,在你失败的代码中,
template <std::enable_if_t<std::is_same_v<T, int>, int> = 0>
C() {}
构造函数正在计算 class (T
) 的模板参数,而不是方法的模板参数。
使用技巧 typename U = T
,您将 class 的模板参数 T
转换为 U
方法的模板参数(您的构造函数案例,但也适用于其他方法)所以 std::enable_if_t
,根据 U
的测试,能够 enable/disable 构造函数。