【问题标题】:Why return-type 'cv' is ignored?为什么返回类型'cv'被忽略?
【发布时间】:2015-01-15 18:46:49
【问题描述】:

至少在“Clang”和“GCC”中。这是一个例子:

char *const InString(char *const p) {

    return gets(p);
}

int main()
{
    static char arr[260];

    char * &&str = InString(arr); //compiles without error - what??????
}

正如你们大多数人可能知道的那样,在'main' 的第二行中,我们将临时返回值('prvalue')绑定到一个'rvalue reference',从而延长了它的生命周期。所以我的问题是这里发生了什么——返回值的“cv”真的被忽略了吗?如果是这样,在标准中这是写在哪里,否则'char *const &&'如何转换为'char * &&'

*需要 ISO C++ 标准认证。

编辑:问题是在“C++ 11”之前,您不允许修改返回值,因为没有引入“右值”,也因为类似:

InString(arr) = nullptr;

毫无意义。但是,现在您可以延长“返回值”的生命周期,因此可以对其进行修改:

auto &&refRetVal = InString(arr);

refRetVal = nullptr;

因此,'const' return 'cv' 很有用。如果上面 'InString' 的返回类型是 'constant',那么对 'nullptr' 的第二次赋值将是非法的。

【问题讨论】:

  • 返回类型中的 cv-qualifier 仅在第一级被忽略,因此 int const foo() 等于 int foo()int const &foo() 不等于 int &foo()。除此之外,我不确定你在问什么......
  • 我问的是返回值临时“prvalue”,从 C++11 开始,它的生命周期可以扩展,因此修改它变得有用,所以“const”cv。
  • @FISOCPP:总是可以通过右值表达式修改临时变量(尽管我承认存在一两个非常小的限制)。这在 C++11 中并不新鲜。只是,在您的示例中,您必须摆弄const_cast 或调用mutable 成员函数来执行此操作,因为首先您只能将临时绑定到const ref .但是,如果您考虑像std::cout << (std::stringstream() << 123).rdbuf(); 这样的简单示例,那么它会变得更加清晰。
  • "在 'C++ 11' 之前,您不允许修改返回值,因为没有引入 'rvalues'" - 完全是垃圾,C++ 一直都有 rvalues,您可以随时修改返回值

标签: c++ c++11 constants language-lawyer return-type


【解决方案1】:

考虑过@dyp提到的引用,即[expr]/6:

如果纯右值最初的类型为“cv T”,其中T 是 cv-unqualified 非类,非数组类型,的类型 在进行任何进一步分析之前,将表达式调整为T

结论比较简单:由于InString(..)这个表达式是prvalue,所以InString(..)(引用的初始化器)的类型简单地调整为char*,这显然是引用兼容目标引用的类型(也是char*)。换句话说,您添加的const 在确定函数调用表达式的类型时会被忽略(但在查看函数时它不会被忽略输入本身!)。

但是,对于标量纯右值,引用永远不会直接绑定到初始化表达式,而是初始化一个临时对象并将引用绑定到它:

int&& i = 4; // Temporary initialized with 4 and bound to i

int const f();
int&& ref = f(); // Initializer expression has type int - same as above

【讨论】:

  • 啊,是的,没错。我没有从其他答案中得到这个。这绝对是最好的解释。
  • 这确实是我在 C++ 中遇到的最奇怪的规则之一。我想我在尝试绑定到推断类型的左值引用时已经学会了:如果g 返回一个 const 非类类型,auto& x = g(); 不起作用。
  • @dyp 现在我觉得可以写一本关于引用初始化规则的短书了。每次我尝试提供分析时,它都会变得更加复杂。 (顺便说一句:感谢您纠正我。:o))
  • 可能原因是非类非数组类型的纯右值是不可变的——它们是值,而不是对象。即使我们尝试将它们绑定到右值引用,它们也不是直接绑定的,而是一个用它们初始化的对象。我认为非类非数组类型的纯右值被视为真正的 values,而不是 objects
  • 是的,整个初始化主题相当复杂。最近,我认为 function lvalues 出现在 ref init 中是因为没有函数类型的右值。有时它看起来像是语言中晦涩的部分的集合。
【解决方案2】:

返回类型中的 cv-qualifier 仅在第一级被忽略,因此 int const foo() 等于 int foo()int const &foo() 不等于 int &foo()

在您的情况下,您的函数 char *const InString() 等效于 char *InString()

关于char *&&str = InString(arr) 的绑定。函数的返回是一个右值(临时),str 是一个右值引用,所以这是意料之中的。当然,临时的生命周期会扩展到引用的范围。

顺便说一句,你的代码,用-Wextra 编译得到 CLang++:

警告:返回类型上的 'const' 类型限定符无效 [-Wignored-qualifiers]

在 G++ 中:

警告:在函数返回类型 [-Wignored-qualifiers] 上忽略类型限定符

【讨论】:

  • 我需要的是标准论文资格。
  • @FISOCPP:我认为您的意思是“C++ 标准引用/引用”。
  • 一般没有const非类非数组类型的表达式。 const 在返回类型上不会被忽略。检查类类型。
  • "一般没有 const 非类非数组类型的表达式" 对不起,我必须限定:没有 prvalue非常量、非数组类型的表达式。
猜你喜欢
  • 1970-01-01
  • 2021-01-13
  • 2021-11-06
  • 2019-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多