从替代方案构建的变体中返回构造

return a constructible from a variant being constructed from an alternative

本文关键字:返回 方案 构建      更新时间:2023-10-16

可以拥有一个可以从变体中构造的结构(例如,从std :: variant)构造,并且要返回从变体的替代方案之一中隐含构建的这种结构?p>考虑以下代码:

#include <utility>
struct type1_t
{
};
struct type2_t
{
};
struct variant
{
    /*template <typename T>
    variant(T&& t)
    {}*/
    variant(type1_t){}
};
struct var_holder_t
{
    var_holder_t(variant v)
        : m_var(std::move(v))
    {}
private:
    variant m_var;
};
var_holder_t foo()
{
    return type1_t{ };  // <====== offending line
}

MSVC 2017,2019允许这样做,但GCC和Clang并未编译。更改为另一个变体的构造函数,甚至使用boost ::变体或std ::变体无济于事。

值得注意的是,将有问题的线更改为return {type1_t{ }};使其以某种方式编译。目前,我迷路了,尽管从技术上讲,添加两个额外的{}并没有造成太大的伤害可读性,但现在我会坚持这一点,只是希望答案。

还可以使var_holder_t的构造函数模板(转发)有助于它可以直接从type1_t构造的var_holder_t(在性能方面非常好),但是目前我想保留var_holder_t完全非template-思想,设计)是随便写的简单代码。


更新:实际上让我感到困惑的是,Clang发出了此消息:

note: candidate constructor not viable: no known conversion from 'type1_t' to 'variant' for 1st argument var_holder_t(variant v)

这很奇怪,因为显然有从type1_t转换为variant,但看起来只是伪造的诊断。将其汇总在一起,我认为我可以提出一个简单的原因,使上面的构建不起作用:它需要两个隐式转换,但是规则仅考虑一个。

以下语句有效,因为正在执行列表初始化。

return {type1_t{ }};

复制列表initialization

return { arg1, arg2, ... } ;    (8) 

列表初始化在以下情况下执行:
...
直接列表初始化(考虑了明确和不明显的构造函数)

...
8)在带有支撑列表的返回语句中,用作返回表达式, list-Initialization初始化返回的对象

此处用type1_t对象初始化var_holder_t,并且可以按预期工作。