为什么从函数返回 const 没有被检测为 const?

ara*_*net 5 c++ runtime-error metaprogramming constants c++17

我有一个程序,它取决于 的结果std::is_same_v <const value_t, decltype(value)>。但是,我发现当函数传递给这个表达式时,结果是意外的,导致我出现错误。

我认为返回的函数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;
}                     
Run Code Online (Sandbox Code Playgroud)

为什么会这样呢?我怎样才能确保std::is_same_v <const value_t, decltype(value)>两者std::is_same_v <const value_t, decltype(func())>都返回 true?

use*_*522 7

y()是纯右值表达式。该表达式的类型不是const int, but int

这是因为纯右值非类非数组表达式的类型已去除其 cv 限定符。

换句话说,如果您使用类类型,它会起作用,但不适用于非类类型。

这就是语言的工作原理。const inta和纯右值之间没有区别int,其他基本类型也类似。它们只是限定符没有用的值。

相反,表达式x是左值,而不是纯右值,因此 cv 限定符不会被删除。const通过- 限定左值和非- 限定左值引用对象之间存在差异const

但即使如此,decltype直接应用于非括号名称实际上也不会考虑表达式的类型,而是考虑命名实体的声明类型。这是一个特殊情况。decltype((x))会考虑表达式类型和yield const int&,添加左值引用,因为x是左值。

std::invoke_result还指定返回decltypeINVOKE 表达式的 ,所以它也会有同样的问题。


const您可以从函数类型的返回类型中获取-qualified 类型。一种典型的方法是基于函数类型的部分专业化。不幸的是,正确地执行此操作非常麻烦,因为必须编写大量专业化内容才能涵盖所有情况。y如果重载或通用 lambda/函子,它也将不起作用。

我的猜测是,egboost::callable_traits::return_type是以这种方式实现的,并且会产生const-qualified 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;
}
Run Code Online (Sandbox Code Playgroud)