c++11 - 返回统一的初始化引用是否有效?

标签 c++11 gcc reference clang uniform-initialization

此代码示例是否有效?

using ref = char&;

ref foo(ref x) {
  return ref{x};
}

int main() {
  char a;
  foo(a);
  return 0;
}

似乎:
  • clang 3.5 说是
  • gcc 4.9 说不
    main.cpp: In function 'char& foo(ref)':
    main.cpp:4:15: error: invalid cast of an rvalue expression of type 'char' to type 'ref {aka char&}'
       return ref{x};
                   ^
    

  • http://coliru.stacked-crooked.com/a/cb6604b81083393f

    那么哪个编译器是正确的呢?还是未指定?

    它很容易通过以下方式克服 gcc 构建错误:
  • 使用括号代替大括号
    ref foo(ref x) {
      return ref(x);
    }
    
  • 通过命名返回值
    ref foo(ref x) {
      ref ret{x};
      return ret;
    }
    

  • 选项 1. 破坏统一初始化,选项 2. 添加无用的代码行。

    这里已经提出了类似的问题:
    Why can't I initialize a reference in an initializer list with uniform initialization?

    但提到 pr50025 在 gcc 4.9 中已修复。

    我知道上面的代码示例毫无用处,
    但我故意将其过度简化以指出问题所在。
    在现实生活中,代码问题可以隐藏在一个通用函数中,例如:
    #include <utility>
    template <typename Tp, typename... Us>
    Tp bar(Us&&... us) {
      return Tp{std::forward<Us>(us)...};
    }
    

    最佳答案

    这似乎是标准中的一个遗漏,其中 GCC 正在执行标准要求的内容,而 clang 正在执行可能的预期目标。

    从 C++11(强调我的):

    5.2.3 Explicit type conversion (functional notation) [expr.type.conv]

    1 A simple-type-specifier (7.1.6.2) or typename-specifier (14.6) followed by a parenthesized expression-list constructs a value of the specified type given the expression list. If the expression list is a single expression, the type conversion expression is equivalent (in definedness, and if defined in meaning) to the corresponding cast expression (5.4). [...]

    [...]

    3 Similarly, a simple-type-specifier or typename-specifier followed by a braced-init-list creates a temporary object of the specified type direct-list-initialized (8.5.4) with the specified braced-init-list, and its value is that temporary object as a prvalue.



    对于 braced-init-list 的情况,标准没有指定这就像 C 风格的强制转换一样工作。它不会:
    typedef char *cp;
    int main() {
      int i;
      (cp(&i)); // okay: C-style casts can be used as reinterpret_cast
      (cp{&i}); // error: no implicit conversion from int * to char *
    }
    

    不幸的是,T(expr)相当于(T)expr也是函数转换不一定产生纯右值的一个异常(exception)。该标准未能为使用花括号初始化列表到引用类型的功能转换指定类似的异常。因此,在您的示例中,ref{x}构造 ref 类型的临时变量,从 {x} 初始化的直接列表.然后将该临时值视为纯右值,因为这就是标准所说的行为应该是什么,并且该纯右值不能用于绑定(bind)到左值引用。

    我强烈怀疑,如果将其提交给 ISO C++ 委员会,标准将被更改为要求 clang 的行为,但根据标准的当前措辞,我认为 GCC 是正确的,至少对于您的具体示例是正确的。

    您可以省略ref,而不是添加变量或切换到括号。 ( Tp ) 来避免这个问题:
    template <typename Tp, typename... Us>
    Tp bar(Us&&... us) {
      return {std::forward<Us>(us)...};
    }
    

    关于c++11 - 返回统一的初始化引用是否有效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28199177/

    相关文章:

    c - 如何固定结构的分配大小

    objective-c - iOS是否会更改对象的引用?

    c# - 如何在 C# 中存储对整数的引用?

    c++ - 强制实例化模板类中的静态成员

    c++ - 字符串与十六进制值的用户定义文字

    c++ - 如何在C++中制作无限序列

    c++ - 如何将 Qt 库连接到标准 C++ 项目?

    c++ - 我应该在我的 C++ std 随机分布上调用 reset() 来清除隐藏状态吗?

    c++ - 内联汇编中的弱符号和自定义部分

    c++ - c++中使用引用重命名变量