此问题在此处已有答案:
Why does the compiler warn about const on a return type being meaningless? [duplicate](6个答案)
Does it make sense to return fundamental types by const value?(11个答案)
4天前关闭。
我有一个依赖于std::is_same_v <const value_t, decltype(value)>
结果的程序。然而,我发现当函数传递给这个表达式时,结果是意外的,这给我带来了bug。
我认为返回const value_t
的函数将被视为与const value_t
相同,但情况似乎并非如此,因为std::is_same_v <value_t, decltype(func())>
返回true。
我尝试使用std::as_const,static_cast,从constexpr函数返回这些值,但它们都没有像预期的那样工作。
一个最小的,可重复的例子:
#include <type_traits>
#include <iostream>
inline const int x = 1;
/// A constant integer variable.
inline const int y() {return x;}
/// A constant integer function returning <x>.
int main()
{
/// <x> successfully passes as being a constant.
std::cout << std::is_same_v <const int, decltype(x)> << " ";
/// But returning it from a function (<y>) does not.
std::cout << std::is_same_v <const int, decltype(y())> << std::endl;
}
字符串
为什么会这样?我如何确保std::is_same_v <const value_t, decltype(value)>
和std::is_same_v <const value_t, decltype(func())>
都返回true?
2条答案
按热度按时间bqf10yzr1#
y()
是一个纯右值表达式。这个表达式的类型不是const int
,而是int
。这是因为纯右值类型的非类非数组表达式的cv限定符被去掉了。
换句话说,如果你使用类类型,它将工作,但不与非类类型。
这就是语言的工作方式。
const int
和int
纯右值之间没有区别,其他基本类型也是如此。它们只是限定符没有用处的值。相反,表达式
x
是左值,而不是右值,因此cv限定符没有被剥离。通过const
限定和非const
限定的左值引用对象之间存在差异。但即使这样,直接应用于非括号名称的
decltype
实际上也不会考虑表达式的类型,而是考虑命名实体声明的类型。这是一种特殊情况。decltype((x))
会考虑表达式类型并产生const int&
,添加左值引用,因为x
是左值。std::invoke_result
也被指定为返回INVOKE表达式的decltype
,因此它将具有相同的问题。您可以从函数类型的返回类型中获得
const
限定类型。一个典型的方法是基于函数类型的部分专门化。不幸的是,正确地做到这一点非常麻烦,因为必须编写大量专门化来覆盖所有情况。如果y
重载或泛型lambda/functor,它也不会工作。我的猜测是,例如
boost::callable_traits::return_type
是以这种方式实现的,并将产生const
限定的int
。它会产生预期的结果(参见https://godbolt.org/z/7fYn4q9vs):
字符串
iyfjxgzm2#
这是因为expr#6指出:
如果纯右值最初的类型为
cv T
,其中T
是cv限定的非类、非数组类型,则在进行任何进一步分析之前,表达式的类型将调整为T
。这意味着在你的特定示例中,由于调用表达式
y()
是const int
类型的纯右值**,因此上面的引用适用于它,因此在进一步分析之前它将被调整为int
,因为int
是内置类型而不是类类型,因此在这种情况下结果是false
。另一方面,
decltype(x)
给出了x
的声明类型,它是const int
而不是int
,因此在这种情况下结果是true
。请注意,即使你写
decltype((x))
,结果也将是true
,因为当x
用作表达式时,它是一个左值,因此上面的引用不适用于它(并且没有对const int
进行调整)。