3

std::variant除了(或什至代替)get< T >()自由函数(草案的第 568 页)之外,使类的一部分成为显式转换(替代)运算符重载集有什么缺点?

template<class... Types>
class variant
{
    template<class T>
    explicit operator const T& () const&;
    template<class T>
    explicit operator T& () &;
    template<class T>
    explicit operator const T&& () const &&;
    template<class T>
    explicit operator T&& () &&;
};

在某些情况下不安全吗?为什么我们需要自由get()函数(即“类型”版本,而不是“索引”版本),当变体暴露一个值语义时(引自草案):

变体对象保存并管理值的生命周期。

使变体显式可转换为替代方案还不够,但仍可从替代方案隐式构造吗?

我知道,接口的统一性是件好事(我记得我们需要get< I >()get< T >()

4

3 回答 3

3

我能想到几个缺点:

  • std::variant可以保存cv void,但返回cv void&cv void&&的转换函数是非法的,并且永远不会调用到cv void的转换函数([class.conv.fct] /1);
  • a 有可能std::variant持有一个也可以从它构造的类型,例如:std::variant<std::monostate, std::any> v; std::any a{v};- 在这种情况下应该发生什么?

此外,目前可以将函数返回T,将其转换为函数返回std::variant<T, U>,并期望编译器检测到所有需要更改代码的情况;T在代码复制或绑定引用的任何情况下使用转换函数T会导致错误:

int f();
int i{f()};    // OK

// f() changes to:
std::variant<int, std::string> f();
int i{f()};    // can now throw std::bad_variant_access
于 2016-09-19T11:09:55.970 回答
1

1)我认为有一种情况是没有争议的,如果std::variant只有一种情况。(这可能发生在通用代码中。)然后变体应该(隐式地,IMO)可转换为该单一类型。

std::variant<double> v(5.3);
...
double d; d = v; // should be ok

2)对于其他非退化情况,我认为它应该是可转换的(明确地),就像那样std::get。我只会为原始 variant的情况(而不是任意类型)这样做。

std::variant<double, int> v(5.3);
...
double d{v}; // should be ok, but can throw

我不认为因为void案件而没有该功能的借口是好的。在最坏的情况下,void是问题,而不是variantvoid案件应由monostate(或将来由“常规void”)处理。

所以总而言之,我支持你的想法,除了我会限制转换运算符。

另外,我会返回一个副本而不是引用(绝对不是非常量引用)。原因是使用引用可以将变体内容置于无效状态(就像原始联合会发生的那样),或者如果变体稍后更改大小写,则引用本身可能处于无效状态。

[编辑:我收回这一点,引用一直无效,这没关系,例如,如果您引用向量的元素并且稍后调整向量的大小。]

template<class... Types>
class variant
{
    template<class T>
    explicit operator T&() const{return std::get<T>(*this);}
    ...
};

template<class T>
class variant
{
    /*implicit*/ operator T&() const{return std::get<T>(*this);}
    ...
};

鉴于缺少该功能,一些临时解决方法,

一个。派生std::variant并添加这些功能。从变体派生或聚合似乎是一种常见的模式。

湾。重载变体案例的函数,以便它可以直接接受变体并立即调用原始函数 over std::get<type>(...)

于 2018-06-02T21:27:08.927 回答
0

我不建议的主要原因如下:

  • optional 没有
  • 可选有一个explicit operator bool()has_value()或没有?)
  • 变体和可选应尽可能保持一致。

但鉴于正确的论点,这肯定可以在未来的修订中改变。

于 2017-03-30T06:44:09.317 回答