我已经开始学习C ++,目前我正在尝试开始使用模板,所以如果我的措辞不是100%准确,请耐心等待。
我使用以下文献:
第一本书介绍了以下模板功能
template<typename T1, typename T2>
auto max(T1 a, T2 b) -> decltype(b<a?a:b) {
return b < a ? a : b;
}
并声明此定义有一个缺点,因为T1
或T2
可能是一个引用,因此返回类型可以是引用类型。
然而,第二本书指出,如果ParamType
,在我们的例子中T1
和T2
既不是指针也不是引用,这对我们的情况来说是正确的,则忽略调用表达式的引用部分。
用例子说明
template<typename T>
void f(T param);
int x = 27; // as before
const int cx = x; // as before
const int& rx = x; // as before
f(x); // T's and param's types are both int
f(cx); // T's and param's types are again both int
f(rx); // T's and param's types are still both int
现在我想知道,第一个代码片段的返回类型是引用类型,甚至可能是多么可能?
他们都是对的:
请参阅cppinsights中生成的代码
template<typename T1, typename T2>
auto max(T1 a, T2 b) -> decltype(b<a?a:b) {
return b < a ? a : b;
}
template<typename T1, typename T2>
auto max2(T1 a, T2 b){
return b < a ? a : b;
}
max(j,i);
max2(j,i);
将'生成':
template<>
int & max<int, int>(int a, int b)
{
return b < a ? a : b;
}
template<>
int max2<int, int>(int a, int b)
{
return b < a ? a : b;
}
问题是关于C ++ 11 -> decltype(b<a?a:b)
如果删除它(在C ++ 14及更多版本中)该函数将不再返回引用
static_assert( is_same_v<decltype(i),int> );
static_assert( is_same_v<decltype((i)),int&> );
static_assert( is_same_v<decltype(i+j),int> );
static_assert( is_same_v<decltype(true?i:j),int&> );
见https://en.cppreference.com/w/cpp/language/operator_other#Conditional_operator
4)如果E2和E3是相同类型和相同值类别的glvalues,则结果具有相同的类型和值类别[...]
5)否则,结果是prvalue [...]
在C ++中意味着:
static_assert( is_same_v<decltype(true?i:j),int&> ); // E2 and E3 are glvalues
static_assert( is_same_v<decltype(true?i:1),int> ); // Otherwise, the result is a prvalue
因为T1或T2可能是引用,所以返回类型可以是引用类型。
我认为这是错误引用的。返回类型可以是引用类型,但出于不同的原因。
如果你在second book再往前走一点。在第3项中,您将找到问题的答案。
将decltype应用于名称会生成该名称的声明类型。名称通常是lvalue表达式,但这不会影响decltype的行为。然而,对于比名称更复杂的左值表达式,decltype通常确保报告的类型是左值引用。也就是说,如果名称以外的左值表达式具有类型T,则decltype将该类型报告为T&。
然而,这种行为的含义值得注意。在
int x = 0;
x是变量的名称,因此decltype(x)是int。但是在括号中包含名称x - “(x)” - 会产生比名称更复杂的表达式。作为名称,x是左值,C ++也将表达式(x)定义为左值。因此,decltype((x))是int&。在名称周围加上括号可以改变decltype为其报告的类型!
现在唯一的问题是:
b<a?a:b
是左值吗?
4)如果E2和E3是相同类型和相同值类别的glvalues,则结果具有相同的类型和值类别,并且如果E2和E3中的至少一个是比特字段则是比特字段。
所以a
和b
是左值,如果它们属于同一类型,b<a?a:b
也将是左值。看到一个很好的解释here。
这意味着max(1, 2)
调用的返回类型将是int&
而formax(1, 2.0)
将是int