模板参数是否可以是引用类型?
Is it possible for the template parameter to be a reference type?
我已经开始学习 C++,目前正在尝试开始使用模板,所以如果我的措辞不是 100% 准确,请多多包涵。
我正在使用以下文献:
- C++ 模板:完整指南(第 2 版)
- 有效的现代 C++:42 种改进 C++11 和 C++14 使用的具体方法
第一本书看看下面的模板函数
template<typename T1, typename T2>
auto max(T1 a, T2 b) -> decltype(b<a?a:b) {
return b < a ? a : b;
}
并声明此定义有一个缺点,因为 T1
或 T2
可能是引用,因此 return 类型可能是引用类型。
然而,第二本书指出,如果 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
现在我想知道,第一个代码片段的 return 类型怎么可能是引用类型?
他们都是对的:
中生成的代码
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);
会 'generate' :
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 及更高版本中),该函数将不再 return 引用
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) If E2 and E3 are glvalues of the same type and the same value category, then the result has the same type and value category [...]
5) Otherwise, the result is a 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
since T1 or T2 might be a reference, so that the return type could be a reference type.
我认为这是错误引用。 return 类型可能是引用类型,但原因不同。
如果你在你的 second book 中走得更远一点。在第 3 项中,您会找到问题的答案。
Applying decltype to a name yields the declared type for that name. Names are typically lvalue expressions, but that doesn’t affect decltype’s behavior. For lvalue expressions more complicated than names, however, decltype generally ensures that the type reported is an lvalue reference. That is, if an lvalue expression other than a name has type T, decltype reports that type as T&.
There is an implication of this behavior that is worth being aware of, however. In
int x = 0;
x is the name of a variable, so decltype(x) is int. But wrapping the name x in parentheses—“(x)”—yields an expression more complicated than a name. Being a name, x is an lvalue, and C++ defines the expression (x) to be an lvalue, too. decltype((x)) is therefore int&. Putting parentheses around a name can change the type that decltype reports for it!
现在剩下的唯一问题是:
b<a?a:b
是左值吗?
4) If E2 and E3 are glvalues of the same type and the same value
category, then the result has the same type and value category, and is
a bit-field if at least one of E2 and E3 is a bit-field.
所以 a
和 b
是左值,如果它们属于同一类型,b<a?a:b
也将是左值。看到很好的解释here.
这意味着 max(1, 2)
调用的 return 类型将是 int&
而 max(1, 2.0)
将是 int
我已经开始学习 C++,目前正在尝试开始使用模板,所以如果我的措辞不是 100% 准确,请多多包涵。
我正在使用以下文献:
- C++ 模板:完整指南(第 2 版)
- 有效的现代 C++:42 种改进 C++11 和 C++14 使用的具体方法
第一本书看看下面的模板函数
template<typename T1, typename T2>
auto max(T1 a, T2 b) -> decltype(b<a?a:b) {
return b < a ? a : b;
}
并声明此定义有一个缺点,因为 T1
或 T2
可能是引用,因此 return 类型可能是引用类型。
然而,第二本书指出,如果 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
现在我想知道,第一个代码片段的 return 类型怎么可能是引用类型?
他们都是对的:
中生成的代码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);
会 'generate' :
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 及更高版本中),该函数将不再 return 引用
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) If E2 and E3 are glvalues of the same type and the same value category, then the result has the same type and value category [...]
5) Otherwise, the result is a 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
since T1 or T2 might be a reference, so that the return type could be a reference type.
我认为这是错误引用。 return 类型可能是引用类型,但原因不同。
如果你在你的 second book 中走得更远一点。在第 3 项中,您会找到问题的答案。
Applying decltype to a name yields the declared type for that name. Names are typically lvalue expressions, but that doesn’t affect decltype’s behavior. For lvalue expressions more complicated than names, however, decltype generally ensures that the type reported is an lvalue reference. That is, if an lvalue expression other than a name has type T, decltype reports that type as T&.
There is an implication of this behavior that is worth being aware of, however. In
int x = 0;
x is the name of a variable, so decltype(x) is int. But wrapping the name x in parentheses—“(x)”—yields an expression more complicated than a name. Being a name, x is an lvalue, and C++ defines the expression (x) to be an lvalue, too. decltype((x)) is therefore int&. Putting parentheses around a name can change the type that decltype reports for it!
现在剩下的唯一问题是:
b<a?a:b
是左值吗?
4) If E2 and E3 are glvalues of the same type and the same value category, then the result has the same type and value category, and is a bit-field if at least one of E2 and E3 is a bit-field.
所以 a
和 b
是左值,如果它们属于同一类型,b<a?a:b
也将是左值。看到很好的解释here.
这意味着 max(1, 2)
调用的 return 类型将是 int&
而 max(1, 2.0)
将是 int