我试图std::enable_if
更好地理解通用引用,但我对我的代码中发生的事情有点困惑。
首先,我注意到人们似乎以std::enable_if
两种不同的方式使用:
template<typename T, std::enable_if<condition, T>::type* = nullptr>
或类似的东西。template<typename T> std::enable_if_t<condition, T> myfunc() {...}
或类似的东西。
我理解第二个发生了什么,但我对为什么有人会使用第一个感到困惑。除了向模板添加另一个参数之外,这实现了什么?这是 SFINAE 的事情吗?
使用enable_if
. 这是我的代码和我得到的结果。请注意,我使用的是 Howard Hinnant 的类型打印代码,来自“ Is it possible to print a variable's type in standard C++? ”,为简洁起见,我将在此省略。
无论如何,该功能conditionless
似乎适用于一切。
我很困惑is_integral
and decay
,你可以在开头看到main
。我得到输出:
true: unsigned long
false: unsigned long
false: unsigned long
false: unsigned long
我不知道为什么最后三个是假的。
然后我遇到了问题(在下面的源代码中标记为 1 和 2),当以enable_if
上述两种方式中的任何一种使用时,它们在接受整数或浮点类型的左值时拒绝编译。
为简洁起见,省略了标题和类型打印代码:
template<typename T>
void conditionless(T&& val) {
std::cout << "conditionless(" << val << ")\n";
}
template<typename T, typename std::enable_if<std::is_integral_v<T>, T>::type* = nullptr>
void outputIntType(T&& val) {
std::cout << "outputIntType(" << val << ")\n";
}
template<typename T>
typename std::enable_if_t<std::is_floating_point_v<T>>
outputFloatType(T&& val) {
std::cout << "outputFloatType(" << val << ")\n";
}
int main() {
size_t sz = 1;
size_t &ref = sz;
// All of these report as having type "unsigned long", but for some reason, the first reports true for is_integral, and
// the other three report false.
std::cout << std::boolalpha << std::is_integral_v<decltype(sz)> << ": " << type_name<decltype(sz)>() << '\n';
std::cout << std::boolalpha << std::is_integral_v<std::decay<decltype(sz)>> << ": " << type_name<std::decay<decltype(sz)>::type>() << '\n';
std::cout << std::boolalpha << std::is_integral_v<decltype(ref)> << ": " << type_name<decltype(sz)>() << '\n';
std::cout << std::boolalpha << std::is_integral_v<std::decay<decltype(ref)>> << ": " << type_name<std::decay<decltype(ref)>::type>() <<'\n';
// This works fine.
conditionless(sz);
conditionless(2UL);
conditionless(2L + 1);
// ******* 1 *******
// This fails and claims no matching function call to outputIntType(size_t&)
// template argument deduction / substitution failed:
// error: no type named 'type' in 'struct std::enable_if<false, long unisgned int&>'
// I'm particularly confused about why the is_integral evaluates to false.
//outputIntType(sz);
// These work fine.
outputIntType(2UL);
outputIntType(2L + 1);
double pi = 3.1415926535;
// These work fine.
conditionless(pi);
conditionless(2 * pi);
conditionless(0.00000001);
// ******* 2 *******
// This fails as well:
// main.cpp: In function 'int main()':
// error: no matching function for call to 'outputFloatType(double&)'
// note: candidate: 'template<class T> std::enable_if_t<is_floating_point_v<T> > outputFloatType(T&&)'
// template argument deduction/substitution failed:
// outputFloatType(pi);
// These work fine.
outputFloatType(2 * pi);
outputFloatType(0.00000001);
}
任何人都可以给我关于两种不同用途enable_if
以及为什么我的代码enable_if
拒绝接受左值的任何见解,将不胜感激。