1

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

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 &' 

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

4

2 回答 2

3

操作员的条件是什么并不重要?:。结果类型被计算为第二个和第三个操作数的通用类型。以下是如何计算运算符的常用类型和值类别的部分内容?:,请参阅cppreference.com了解完整详细信息:

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

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

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

这就是函数编译的原因。通用类型总是使得两种输入类型都可以转换为它。这也是为什么函数在类型相等时具有未定义行为的原因,因为 thendecltype给出了引用,因此您将返回对函数参数之一的引用。

decltype(a<b ? a:a)不适用于不同的类型,因为 and 的通用类型a如上所述a,是 . 的类型的引用a。如果bthen 具有不同的不相关类型,则 的结果a > b ? a : b将是无法绑定到左值引用的纯右值。

于 2020-01-27T07:18:45.430 回答
1

你可能认为

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,但这是完全合法的,因为返回类型变为 . 之后的任何类型->

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

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是因为作为三元运算符一部分的两种类型都是glvalues ,这里说:

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

所以结果a < b ? a : aglvalue. 这就是为什么您需要删除引用。结果a < b ? a : b是 a prvalue,因此您不需要删除引用。

于 2020-01-27T07:17:36.227 回答