【问题标题】:C++11 - declaring non-static data members as 'auto'C++11 - 将非静态数据成员声明为“自动”
【发布时间】:2012-07-03 10:00:11
【问题描述】:

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

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

GCC 4.7 拒绝上述代码,但接受 int x = 5;

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

【问题讨论】:

  • 允许以这种方式声明静态数据成员,但不能声明非静态数据成员(参见 C++11 §7.1.6.4 中允许的auto 使用列表)。在我的脑海中,我想不出一个很好的理由来禁止它,尽管我肯定会认为这是对auto的滥用。
  • @JamesMcNellis:你为什么认为这是对auto的滥用?在类范围内拥有一个具有长/复杂类型名称的变量(因此最好使用auto 而不是写出它的类型)与在本地范围内拥有一个变量有什么区别?
  • 在块范围内,我知道变量是如何使用的。在类范围或命名空间范围内,我不一定知道变量是如何使用的。例如,考虑更一般的auto x = f(a, b, c);:我必须找到所有f() 函数并在脑海中执行重载决议以找出x 的类型。至少在本地范围内,我可以查看x 正在做什么,并尝试从中推断出它的类型。 auto 非常有用,但不应该在任何地方使用。
  • @JamesMcNellis:有趣的是,auto 在命名空间范围内是允许的。我不明白为什么类范围会这样被挑出来......
  • 参见this ISOCPP mailing list discussion关于非静态自动成员的原型实现,以及委员会在N3897 Auto-type members中记录的讨论。

标签: c++ c++11 auto variable-declaration


【解决方案1】:

禁止非静态成员的规则在 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 在评论中的解释。

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

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

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

由于这一争议,作者不再提出自动 允许用于非静态数据成员。

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

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

【讨论】:

  • 感谢您挖掘这个,这是一个有趣的理由!
  • 注:最初允许它的提议是N2426
  • @JonathanWakely 真的没有希望看到 C++20 的话题复活了吗?如果允许的话,我的代码中有几个地方会更易读。主要是auto foo_ = Type{...};,所以这种情况已经有帮助了。
  • 这个理由不也适用于decltype(func()) data = func(),现在是合法的吗?
  • 我不明白为什么static 会有所作为。我错过了什么?
【解决方案2】:

对于其他人:

使用 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 通过引用捕获类的成员,则上述场景工作。对于避免使用类型擦除函数的高度可补偿的类,这是一种有用的模式。我经常在嵌入式系统上做的事情。

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

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

【讨论】:

  • 我不明白这是怎么回答的。该类没有声明为“auto”的数据成员。
  • 您获得会员类型自动扣除。这似乎是问题的最终目标。这就是我在一些应用程序中解决作为类成员对 auto 的需求的方法。这是一个真正的解决方法。如顶部所述,对于正在搜索该内容的其他人。
  • 也许一个更大的例子来说明如何使用它会有所帮助,因为我还没有看到它。
  • 当然,采用 lambda 包装器的这个实现。 lambda 的类型是未知的,必须推导出来。 wandbox.org/permlink/wCzrLsPc9k0YErDA 记住这不是 C++11,这只是为了其他有类似问题的人,我想是为了你的好奇心。
  • 我理解并同意。考虑一下:您只需将您的想法散布并让它们几乎全部在 main() ... auto 和 lambdas 中工作。你让一切顺利。然后你需要把它作为一个班级来提供。由于您一直在使用 lambdas 和 auto 并不是一件容易的事。在不可行的边缘。你能做什么?您通常会从 lambdas 回溯到 std::function&lt;&gt;,因为您不能在课堂上自动输入 .. 我希望我能说清楚吗?我只是花了几个小时试图做到这一点,然后我找到了这个答案。 +1
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-02
相关资源
最近更新 更多