c++ 为什么从一个函数返回一个常量不会被检测为常量?[重复]

piok6c0g  于 5个月前  发布在  其他
关注(0)|答案(2)|浏览(63)

此问题在此处已有答案

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_conststatic_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?

bqf10yzr

bqf10yzr1#

y()是一个纯右值表达式。这个表达式的类型不是const int,而是int
这是因为纯右值类型的非类非数组表达式的cv限定符被去掉了。
换句话说,如果你使用类类型,它将工作,但不与非类类型。
这就是语言的工作方式。const intint纯右值之间没有区别,其他基本类型也是如此。它们只是限定符没有用处的值。
相反,表达式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):

#include <type_traits>
#include <iostream>
#include <boost/callable_traits/return_type.hpp>
   
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)> << " ";
   
    /// And returning it from a function (<y>) now does as well.
    std::cout << std::is_same_v <const int, boost::callable_traits::return_type_t<decltype(y)>> << std::endl;
}

字符串

iyfjxgzm

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进行调整)。

相关问题