模板参数是否可能是引用类型?

时间:2019-04-18 12:36:07

标签: c++ templates reference decltype template-deduction

我已经开始学习C ++,目前我正在尝试使用模板,因此,如果我的措辞不是100%准确,请多多包涵。

我正在使用以下文献:

  • C ++模板:完整指南(第2版)
  • 有效的现代C ++:改善C ++ 11和C ++ 14使用的42种特定方法

第一本书介绍了以下模板功能

template<typename T1, typename T2>
auto max(T1 a, T2 b) -> decltype(b<a?a:b) {
  return b < a ? a : b;
}

并指出此定义有一个缺点,因为T1T2可能是引用,所以返回类型可能是引用类型。

但是,第二本书指出,如果ParamType(在我们的情况下为T1T2既不是指针也不是引用,对于我们的情况是正确的)调用表达式的引用部分将被忽略。

示例说明

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

现在我想知道,第一个代码段的返回类型是引用类型怎么可能?

2 个答案:

答案 0 :(得分:5)

它们都是正确的:

查看在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是相同类型和相同值类别的glvalue,则结果具有相同的类型和值类别[...]

     

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

答案 1 :(得分:1)

  

因为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是左值吗?

来自cppreference

  

4)如果E2和E3是相同类型和相同值的glvalues   类别,则结果具有相同的类型和值类别,并且是   如果E2和E3中的至少一个是位字段,则为位字段。

因此ab是左值,并且如果它们具有相同的类型,b<a?a:b也将是左值。见一个很好的解释here

这意味着max(1, 2)调用的返回类型将是int&max(1, 2.0)的返回类型将是int