std::tuple和std::pair支持聚合初始化吗?

9

聚合初始化 需要保证没有用户提供的构造函数,但是 std::tuplestd::pair 类有一大堆重载构造函数。从核心语言的角度来看,这些构造函数算不算用户提供的甚至用户声明的

使用 C++17,将可以编写以下代码(更新/澄清:其中 nocopy 是一个不能复制或移动的类,例如 std::mutex

auto get_ensured_rvo_str(){
   return std::pair(std::string(),nocopy());
}

编辑:不行,如链接的答案和下面的答案所述。

这需要聚合初始化(为了上下文: C++17中具有不可移动类型和保证RVO的多个返回值(结构化绑定))。

tuplepair是否由特殊的标准语言支持以允许此操作(在存在构造函数的情况下)?:

20.5.2.1 Construction

... EXPLICIT constexpr tuple(const Types&...);

6 Effects: 构造函数使用相应参数的值初始化每个元素。

或者我们可以原则上编写自己的tuplepair吗?


当前示例不需要聚合初始化。请提供一个相关的示例。 - Cheers and hth. - Alf
@songyuanyao,@Alf,我对链接答案的理解是,不可能像那样使用实际构造函数初始化无法复制和移动的成员,它是由聚合初始化驱动的,这并不是真正的构造函数调用。此外,澄清了nocopy也是无法移动的(如链接问题中所述)。 - Johan Lundberg
1
如果我正确理解了被接受的答案,它说“pair”代码将不起作用。 - Revolver_Ocelot
@Recover_Ocelot。与ecatmur的答案正确并且一致。 - Johan Lundberg
1个回答

6

不,tuplepair中没有支持将非移动类型传递给它们的构造函数的功能。正如您所观察到的那样,这是不可能的,因为构造函数参数和元组(或对)成员可以被观察到是不同的对象

// exposition only
template<class... Us>
tuple(Us&&... us) : values{std::forward<Us>(us)...} {}
              ^^ these
                    ^^^^^^ are different objects to these

你需要使用逐段构建:
return std::pair<std::string, nocopy>(std::piecewise_construct,
    std::forward_as_tuple(), std::forward_as_tuple());

Matt Calabrese在std-proposals列表中提出了一个有趣的观点,现在我们已经保证了RVO,因此应该可以编写接受工厂以有效地就地构造其成员的组件:

// hypothetical factory constructor
return std::pair(std::factory_construct,
    [] { return std::string{}; }, [] { return nocopy{}; });

另一个可能的方向是从tuplepair中移除构造函数(或者更现实地,编写没有构造函数的替代组件),并依赖于通过多重继承实现的tuplepair的聚合初始化的新扩展示例

你肯定是对的。这很有趣,因为它为一个没有构造函数的普通聚合体打开了一个用例,就像链接到的问题中所示:template<typename T1,typename T2,typename T3> struct many { T1 a; T2 b; T3 c; }; template<class T1, class T2, class T3> many(T1, T2, T3) -> many<T1, T2, T3>; - Johan Lundberg
我不禁想到,编程语言变得过于复杂而难以使用。有太多重叠的符号。似乎这种情况始于C++14。:( - Cheers and hth. - Alf
ectamur,当您完善了您的答案时,我写了一个跟进问题,与您的更新非常相关。https://dev59.com/RJjga4cB1Zd3GeqPRvZh - Johan Lundberg
1
@Cheersandhth.-Alf:你不需要了解这些东西就能使用语言。不能与“pair”一起使用的不可移动类型甚至不是新的;那是C++98的东西。如果你让你的复制构造函数消失,它就无法工作。唯一变得“复杂”的事情是现在有些情况下你可以使用不可移动对象来初始化聚合体。 - Nicol Bolas
工厂构造位有些笨拙。实际上,我们需要一种高效而简洁的方式来表达“这不是一个Foo,而是在您选择的位置构建Foo的指令”,作为函数参数,并且在调用方面编写它而无需编写lambda。 - Yakk - Adam Nevraumont

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接