繁体   English   中英

c++ 11 带有 decltype 的尾随返回类型无法按预期工作

[英]c++ 11 Trailing return type with decltype does not work as expected

为什么这“按预期”工作? 我的理解是这不应该起作用:

template <class T, class U>
auto x(T a, U b) -> decltype(a<b ? a:b) {
    return a > b ? a : b;
}


int main() {
    cout << x<long, double>(1, 2.01) << endl;
    cout << x<long, double>(5, 2.01) << endl;

}

我尝试了一些其他组合,例如:

template <class T, class U>
auto x(T a, U b) -> decltype(a<b ? a:a) {
    return a > b ? a : b;
}

这样它就不会编译出错实际上第二个组合失败了

compile time error:  Error C2440 'return': cannot convert from 'U' to 'T &' 

这是预期的。 我的理解是,第一个函数也应该因相同的错误而失败,但它工作正常。

?:运算符的条件无关紧要。 结果类型计算为第二和第三操作数的公共类型 以下是如何计算?:运算符的通用类型和值类别的一部分,请参阅cppreference.com以获取完整详细信息:

如果第二个和第三个操作数是相同类型的左值,则结果类型将是该类型的左值。

如果类型是不相关的左值,则有一些更复杂的规则来确定公共类型,但结果将是一个 prvalue,而不是一个左值。 特别是如果这两种类型是算术类型,例如doublelong ,则应用通常的算术转换以获得公共类型。 longdouble的情况下,常见类型是double 这与如果您尝试使用+将两个不同的算术类型相加时将执行的类型计算相同,因此名称通常为算术转换

因此,如果ab具有相同类型,则decltype(a<b ? a:b)将是引用类型,否则它将不是引用类型。

这就是函数编译的原因。 公共类型总是这样,两种输入类型都可以转换为它。 这也是为什么如果类型相等,则函数具有未定义行为的原因,因为decltype会提供引用,因此您将返回对函数参数之一的引用。

decltype(a<b ? a:a)不与不同类型的工作,因为普通型aa是,如上所述,对类型的引用a 如果b具有不同的不相关类型,则a > b ? a : b的结果a > b ? a : b a > b ? a : b将是一个不能绑定到左值引用的纯右值。

你可能认为

template <class T, class U>
auto x(T a, U b) -> decltype(a < b ? a : b) {
    return a > b ? a : b;
}

std::cout << x<long, double>(1, 2.01) << std::endl;
std::cout << x<long, double>(5, 2.01) << std::endl;

不会编译,因为尾随返回类型decltype(a < b ? a : b) ,即内部表达式a < b ? a : b a < b ? a : b与返回表达式a > b ? a : b a > b ? a : b但这完全合法,因为返回类型变为->之后的任何类型。

现在,为什么下面的代码没有编译成功?

template <class T, class U>
auto x(T a, U b) -> decltype(a < b ? a : a) {
    return a > b ? a : b;
}

std::cout << x<long, double>(1, 2.01) << std::endl;
std::cout << x<long, double>(5, 2.01) << std::endl;

这是因为您需要从尾随返回类型中删除引用,如下所示:

#include <type_traits>

template <class T, class U>
auto x(T a, U b) -> typename std::remove_reference<decltype(a < b ? a : a)>::type {
    return (a > b ? a : b);
}

现在它编译成功。 在这里查看

第二个示例在没有std::remove_reference情况下无法编译的原因是因为作为三元运算符一部分的两种类型都是glvalue s, 这里说:

4) 如果E2和E3是同类型同值类别的泛左值,则结果具有同类型和同值类别

所以a < b ? a : a的结果a < b ? a : a a < b ? a : aglvalue 这就是您需要删除引用的原因。 a < b ? a : b的结果a < b ? a : b a < b ? a : b是一个prvalue ,因此,您不需要删除引用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM