gpt4 book ai didi

c++ - std::enable_if 和通用引用的使用差异

转载 作者:行者123 更新时间:2023-11-30 01:36:02 26 4
gpt4 key购买 nike

我正在尝试理解通用引用和 std::enable_if更好,但我对我的代码中发生的事情有点困惑。

首先,我注意到人们似乎使用 std::enable_if以两种不同的方式:

  1. template<typename T, std::enable_if<condition, T>::type* = nullptr>或类似的东西。

  2. template<typename T> std::enable_if_t<condition, T> myfunc() {...}或类似的东西。

我了解第二个中发生的情况,但我对为什么有人会使用第一个感到困惑。除了向模板添加另一个参数之外,它实现了什么?这是 SFINAE 的事吗?

我在使用 enable_if 时也卡在了通用引用上.这是我的代码和我得到的结果。请注意,我使用的是来自“Is it possible to print a variable's type in standard C++?”的 Howard Hinnant 的字体打印代码,为简洁起见,我将在此处省略。

无论如何,函数conditionless似乎一切都很好。

我对 is_integral 很困惑和 decay ,您可以在 main 的开头看到.我得到输出:


true: unsigned long
false: unsigned long
false: unsigned long
false: unsigned long

我不知道为什么最后三个是错误的。

然后我在使用 enable_if 时遇到问题(在下面的源代码中标记为 1 和 2)在上述两种方式中的任何一种中,它们在接受整数或浮点类型的左值时都拒绝编译。

为简洁起见省略了标题和类型打印代码:

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拒绝接受左值将不胜感激。

最佳答案

I'm trying to understand universal references

不鼓励使用该术语。官方术语是“转发引用”


I understand what's happening in the second, but I'm confused about why anyone would use the first. What does that achieve except add another parameter to the template? Is it an SFINAE thing?

全部enable_if_t<B, T>确实评估为 T如果B == true ,否则它会生成无效代码。替换期间产生的无效代码不会导致编译错误 (SFINAE)。

在哪里都没有关系enable_if_t只要它受替换步骤的影响就会出现(例如,可以在返回类型、参数列表、模板参数列表中……)。


and I have no idea why the last three are false.

您忘记访问 ::type在你的std::decay转型。您是在比较特征本身,而不是它的结果。


they refuse to compile when accepting an lvalue of an integral or floating point type.

在标准中有一条关于扣除转发引用的特殊规则。给定转发引用参数 T&& , T如果使用左值 调用函数,则将推导为左值引用

你需要在你的特质中考虑到这一点:

typename std::enable_if_t<std::is_floating_point_v<std::remove_reference_t<T>>>

关于c++ - std::enable_if 和通用引用的使用差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52667753/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com