C++11 - 将非静态数据成员声明为“auto”

问题描述 投票:0回答:3

如果非静态数据成员在声明中被初始化,C++11 是否允许将它们声明为“auto”?例如:

struct S
{
    auto x = 5;  // in place of 'int x = 5;', which is definitely allowed
};

GCC 4.7 拒绝上述代码,同时接受

int x = 5;
.

假设这不是编译器错误,而是标准确实不允许,为什么不呢?它和声明局部变量一样有用

auto
.

c++ c++11 auto variable-declaration
3个回答
71
投票

禁止非静态成员的规则在7.1.6.4第4条:

auto 类型说明符也可用于声明变量 选择语句(6.4)或迭代语句的条件 (6.5), 在 type-specifier-seq 中的 new-type-id 或 type-id 中 new-expression (5.3.4),在 for-range-declaration 中,并在声明一个 静态数据成员,带有出现在类定义 (9.4.2) 的成员规范中的大括号或相等初始化程序。

我发现它的基本原理是静态的here反映了 James McNellis 在评论中的解释。

一个国家机构不喜欢允许汽车类型说明符 非静态。从给作者的电子邮件:

    template< class T >
    struct MyType : T {
      auto data = func();
      static const size_t erm = sizeof(data);
    };

为了确定 X 的布局,我们现在有 2 阶段名称查找和 ADL。请注意,func 可以是类型或函数; 它可以在 T 中找到,MyType 的命名空间,关联的 实例化时 T 的命名空间,全局命名空间,一个 匿名命名空间,或任何受 using 指令约束的命名空间。 小心点,我们可能会为了运气而抛出一些 concept_map 查找。 根据标头包含的顺序,我什至可能会得到不同的 ADL 结果,并打破单一定义规则—— 不需要被诊断。

因为这个争议,作者不再提出auto 允许非静态数据成员。

所以,基本上取决于标题包含的顺序,

data
的类型可能会非常不同。当然,
auto x = 5;
不需要依赖于两阶段名称查找或 ADL,但是,我假设他们将其设为“一揽子”规则,否则,他们将不得不为每个用例制定单独的规则这会使事情变得非常复杂。

在同一篇论文中,作者提议取消这个限制,但是,这个提议似乎已经被拒绝了,可能是由于上述理由,而且无论初始化器是什么,预期的行为都是相同的。


6
投票

对于其他人:

使用 C++17 可以间接(自动推导非静态成员类型)。您需要使用模板和演绎指南来实现它:

template< class data_t>
struct MyType 
{
    data_t data;
    static constexpr auto data_size = sizeof(data_t);

    MyType( data_t && p_data ) : data(p_data) {}
};

template< class data_t>
MyType(data_t &&) -> MyType<std::remove_reference_t<data_t>>;

我不知道如何,但是这个汽车会员真的需要在没有他们的情况下将其变成语言,某些模式几乎是不可能的。

如果 lambda 通过引用捕获类的成员,则上述场景 not 工作。对于避免使用类型擦除函数的高度可补偿类来说,这是一种有用的模式。我经常在嵌入式系统上做的事情。

https://godbolt.org/z/W-K9Uk

您可以使用 placement-new 和 offset_of 将语言修改为提交,允许 lambda 引用不存在的类的成员,但这是荒谬的,不应该是必需的。


1
投票

后来的讨论在 2014 年被公开总结:关键点是默认成员初始化器是一个完整类上下文,但任何成员的类型都不是。还有一点理由是,拥有

会很奇怪
std::vector<int> get_ints();
struct S {
  auto x=get_ints();
  S() : x(7,4) {}
};

使用默认成员初始化器的type,否则完全忽略它。

© www.soinside.com 2019 - 2024. All rights reserved.