【问题标题】:Why does C++ not allow multiple types in one auto statement?为什么 C++ 不允许在一个 auto 语句中使用多种类型?
【发布时间】:2013-10-31 12:50:46
【问题描述】:

2011 C++ 标准引入了新的关键字auto,可以用来定义变量而不是类型,即

auto p=make_pair(1,2.5);                   // pair<int,double>
auto i=std::begin(c), end=std::end(c);     // decltype(std::begin(c))

在第二行中,iend 属于同一类型,称为auto。标准不允许

auto i=std::begin(container), e=std::end(container), x=*i;

x 属于不同类型时。 我的问题:为什么标准不允许最后一行?可以通过将auto 解释为不代表某个要推导的类型,而是指示声明autoany 变量的类型应从其分配的值推导出来允许。 C++11 标准是否有充分的理由不遵循这种方法?

这其实有一个用例,即在for循环的初始化语句中:

for(auto i=std::begin(c), end=std::end(c), x=*i;  i!=end;  ++i, x+=*i)
{ ... }

当变量iendx 的范围被限制为for 循环时。 AFAIK,除非这些变量具有通用类型,否则这在 C++ 中无法实现。 这是正确的吗?(将所有类型放入 struct 的丑陋技巧除外)

在一些可变参数模板应用程序中也可能存在用例。

【问题讨论】:

  • 几乎所有形式为“为什么标准说废话”的问题都有以下答案之一:1)向后兼容 C,2)他们没有时间做其他事情, 3) [在此处插入未经证实的意见]
  • @JohnDibling 我不同意。通常有很好的理由(除了向后兼容性,这似乎不适用于这里)。我想知道这里是否有充分的理由。
  • 约翰说得对。几乎所有这样的问题都以这种形式的答案结束。他并不是说不存在充分的理由。只是它通常不为人所知或记录在案。我不知道,你能得到标准委员会的会议记录吗?看起来你可以:open-std.org/jtc1/sc22/wg21/docs/papers我建议你搜索这些。
  • @DavidHeffernan 很好。但是,该提案不允许在一个auto 语句中使用不同的类型。它只允许对所有以下类型使用第一种类型推导,即auto x=3,y;y 自动为int 时。该论点似乎是一致性:任何形式为type x[=initialier], y[=initialier], ... 的变量声明都应始终只定义相同类型的变量,即使是type=auto

标签: c++ c++11 for-loop auto


【解决方案1】:

我认为这只是与非auto 声明的一致性问题。

这个:

auto n = 42, *p = &n;

相当于:

int n = 42, *p = &n;

其中intint* 类型派生自初始值设定项。在这两种情况下,尽管intint* 是不同的类型,但由于它们的语法关系密切,它们被允许在同一个声明中。 (根据 C 和 C++ 声明几乎遵循的“声明遵循使用”规则,您将 n*p 定义为 int 类型。)

本来可以在同一个声明中允许不相关的类型:

auto n = 42, x = 1.5;

但以上必须等同于两个单独的声明:

int n = 42; double x = 1.5;

我认为添加 auto 时的想法是对语言进行最小的更改,允许从初始化程序推断类型但不更改可能的声明类型。

即使没有auto,您也可以在for 循环头中定义intint*

for (int n = 42, *p = &n; expr1; expr2) { /* ... / }

但您不能同时声明 intdoubleauto 的添加并没有改变这一点。

for 循环的上下文之外,无论如何使用单独的声明通常要好得多。在大多数情况下,将许多不同的声明放入 for 循环中可以说是个坏主意。对于需要大量声明的(可能很少见)情况,您可以将它们放在循环之上,如下所示:

auto i=std::begin(c), end=std::end(c),
for( x=*i;  i!=end;  ++i, x+=*i) {
    // ...
}

如果您想限制范围,请在整个内容周围添加另一组 { }。 (在这种情况下,您可能希望 end 成为 const。)

【讨论】:

  • 好的。但这个论点并不是真正强烈反对多类型auto。但似乎确实使用了这个论点。
  • 如果auto按照您规定的方式工作,那么auto x = 1.5, y = 0;double x = 1.5, y = 0;的含义将不同
【解决方案2】:

根据该功能已接受提案的最终修订版,N1737,一个可能的多声明符auto 实现如下:(来自第 6 节)

我们相信有可能实现一致的形式和 一致的行为。我们通过插入(为了 exposition) 一个中间 __Deduced_type 定义,并应用 这种类型在 as-if 扩展中始终如一:

  // Listing 12
 typedef int __Deduced_type; // exposition only
  __Deduced_type a = 1;
 // decltype(a) is int
 __Deduced_type b = 3.14; // decltype(b) is int
  __Deduced_type * c = new float; // error; decltype(c) would be int *

我们不仅可以通过这种方式实现形式和行为的一致性 调和的表述,我们也处理更复杂的情况。 例如,当前导声明符包含 ptr-operator 时:

 // Listing 13 
auto * a = new int(1), b = 3.14, * c = new float;

我们的表述附加了语义,就像声明一样:

// Listing 14 
 typedef int __Deduced_type; // exposition only
 __Deduced_type * a = new int(1); // decltype(a) is int *
 __Deduced_type b = 3.14; // decltype(b) is int
 __Deduced_type * c = new float; // error; decltype(c) would be int *

正如这个可能的实现所示,更改类型是无效的,因此会导致错误。
以这种方式实现此功能是因为否则它将与其他类型的多变量声明不同。
我记得看到过关于是否允许更改类型的讨论,但我不记得在哪里。 IIRC,他们认为它会更难实现,但另一个原因可能是它被放弃了,因为他们无法就何时选择不同类型(新行为)或何时隐式转换为推导类型达成共识第一个声明的变量(旧行为)。

【讨论】:

  • 这只是从大卫评论链接的文档中复制而来。而且它不允许多类型auto。原因似乎只是与其他语句的一致性,如果必须指定类型,显然不能具有多类型语义。
  • 在我发布这篇文章时,我没有看到大卫的评论;我自己找到了 PDF。
【解决方案3】:

C++17 终于带来了结构化绑定声明,解决了你的问题:

auto [ i, s, f ] = std::tuple(42, "Hello World", 5.0);

这将 i 声明为整数 42,将 s 声明为以零结尾的字符串“Hello World”的const char*,并将 f 声明为双精度数 5.0。

我不知道没有中间 std::tuple 的解决方案。如果您使用完全符合 C++20 的编译器,您还可以使用别名模板来缩写 std::tuple,如下例所示:

template<typename ... ARGS> using T = std::tuple<ARGS ...>;
auto [ i, s, f ] = T(42, "Hello World", 5.0);

这在 C++17 和 C++20 模式下都可以用 g++-10 编译,尽管它实际上应该只在 C++20 模式下编译。 C++17 不允许别名模板的模板参数推导,即使在最简单的情况下,模板参数列表被 1:1 转发给别名模板也是如此。

【讨论】:

    【解决方案4】:

    如果要参考 C++ 2014 工作草案,那么标准允许这样的代码。这是标准草案中的一个示例

    auto x = 5, *y = &x; // OK: auto is int
    

    我想在您的示例中附加它 auto 不能被删除,因为迭代器类型和迭代器的值类型是两种不同的类型。

    【讨论】:

    • 这在 C++11 中已经被允许了,我想。关键是 auto is int我明确没有问的
    • 如果您完整阅读了我的问题,您会注意到我的意思不是auto 代表任何类型。而是auto 应指示推导出变量的类型,但允许在同一auto 语句中使用不同的此类类型。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-08
    • 1970-01-01
    • 2014-08-31
    • 2020-03-19
    相关资源
    最近更新 更多