为什么我不能在任意内容的初始值设定项列表上限定范围?



在现代C++中,以下程序按预期编译和运行:

for(const auto& x : {"hello", "nice", "world"}) {
    cout << x << endl;
}

但是,如果初始值设定项列表中有不同类型的元素,我就无法再编译代码:

for(const auto& x : {"hello", 123, '4'}) {
    cout << x << endl;
}

为什么它不编译并运行?这个初始值设定项列表不能被理解为3-tuple吗?或者experimental::any的初始值设定项列表?还是什么?

注意:

  • 使用g++5.2.1和CCD_ 3;--std=c++17不会改变任何事情
  • 假设我已经包含了所有C++标准库头,以及<experimental/any>
  • 编译器错误当然是unable to deduce ‘std::initializer_list<auto>&&’ from ‘{"hello", 123, '4'}’

这个初始值设定项列表不能被理解为一个三元组吗?或者一个初始值设定项列表的实验::有没有?还是什么?

没有。

该支持的init列表没有类型,因此不能将其推断为类型。它可以用于初始化一些东西。。。但要做到这一点,编译器必须知道"某物"是什么

在基于范围的for语句中,编译器生成该定义的等价物:

auto && __range = {"hello", 123, '4'} ;

但这不是有效的C++,因为支撑的init列表的类型是未知的。

或者experimental::any的初始值设定项列表?

它不可能是std::experimental::any,因为它不在标准中。你不能让编译器神奇地将某些东西解释为其他规范中定义的库类型您需要一个编译器已知的内置any类型才能工作,而这将永远不会被委员会接受(由于动态分配和类型擦除引起的间接性,使用any是有成本的,更不用说在不知道类型的情况下无法在for循环中做一些有用的事情)。

如果你想要any的序列,那么就这么说:

for (auto i : std::initializer_list<std::experimental::any>{ a, b, c})

但是你把什么放在环体里?你必须知道每个元素的类型才能做任何有用的事情,如果你已经知道有多少元素及其所有类型,为什么还要使用循环呢?循环是指重复做同一件事,而不是对几种不同的类型做几种不同的事情。

我建议更好的方法是:

auto op = [](auto i) { /* do something with i */ }
op(a);
op(b);
op(c);

内置语言支持创建元组(不是std::tuple,而是动态生成的匿名结构,类似于lambdas创建匿名函数的方式)当然会很好,但它绝对不会涉及通过any的间接。

您可以使用lambdas:来模拟类似的东西

auto anon_struct = [a, b, c](auto func) { func(a); func(b); func(c); }

这将创建一个捕获abc的lambda,并允许您使用将应用于每个变量的函数来调用它:

auto op = [](auto i) { /* do something with i */ }
anon_struct(op);  // apply op to each "member" of the anon struct

或者可能更有用:

auto anon_struct = [a, b, c](auto visitor) { visitor(a, b, c); }
auto visitor1 = [](auto i, auto j, auto k) { /* do something with i */ }
auto visitor2 = [](auto i, auto j, auto k) { /* do something with j */ }
anon_struct(visitor1);
anon_struct(visitor2);

在标准草案18.9/p1 Initializer list[support.intilist]中,初始值设定项列表类定义为:

template<class E> class initializer_list {
...
}

因此,当您实际提供具有不同类型的聚合初始化列表时,问题是编译器必须选择哪种类型来推导E

最新更新