通过参考存储的C 变体类成员

c++ variant class member stored by reference

本文关键字:成员 参考 存储      更新时间:2023-10-16

我正在尝试尝试使用std ::变种。我正在存储一个std ::变体作为班级的成员。在以下代码中,如果变体是按值存储的,但如果vasector case和自定义对象不起作用,则情况正常,如果该变体是通过参考存储的。为什么是?

#include <variant>
#include <vector>
#include <iostream>

template<typename T>
using VectorOrSimple = std::variant<T, std::vector<T>>;

struct Print {
void operator()(int v) { std::cout << "type = int, value = " << v << "n"; }
void operator()(std::vector<int> v) const { std::cout << "type = vector<int>, size = " << v.size() << "n"; }
};

class A {
public:
    explicit A(const VectorOrSimple<int>& arg) : member(arg) {
        print();
    }
    inline void print() const {
        visit(Print{}, member);
    }
private:
    const VectorOrSimple<int> member;  // const VectorOrSimple<int>& member; => does not work
};

int main() {
    int simple = 1;
    A a1(simple);
    a1.print();
    std::vector<int> vector(3, 1);
    A a2(vector);
    a2.print();
}

请参阅http://melpon.org/wandbox/permlink/vhnkanzhqgoyxu1h有关工作版本,以及http://melpon.org/melpon.org/wandbox/permlink/ppermlink/t5rcx0rcx0imtli4gk5e,该版本称为崩溃的版本:'std :: bad_variant_access' 什么():意外索引"

奇怪的是,当将代码的boost ::变体版本与成员一起存储为参考时,它可以按预期(打印向量尺寸= 3次两次)使用GCC7.0(请参阅此处http://melpon.org/wandbox/permlink/ew3bs1ing383vp6m)并且不起作用(在构造函数中打印vector size = 3,然后使用clang 4.0的vertent print()print()no crast)在clang 4.0(请参阅此处http://melpon.org)/wandbox/permlink/2grf2y8rprod7xdm)。

这很令人困惑。有人可以解释发生了什么吗?谢谢。

它不起作用,因为此语句A a1(simple);创建了临时变体对象!

然后,您继续将该临时性绑定到您的const参考。但是,a1结束后,临时性立即消失了范围,使您获得了悬空的参考。显然,创建副本可以工作,因为它始终涉及使用有效的副本。

可能的解决方案(如果始终复制您的担忧的性能)是接受变体对象旁程,然后将其移入您的本地副本中,例如:

explicit A(VectorOrSimple<int> arg) : member(std::move(arg)) {
    print();
}

这将允许您的构造函数使用lvalues或rvalues调用。对于LVALUE,您的member将通过移动源变体的副本来初始化,并且对于rvalues,源的内容将仅移动两次。

变体是对象。它们包含一组类型之一,但不是其中一种类型。

对变体的引用是对变体对象的引用,而不是对包含类型之一的引用。

参考包装器的变体可能是您想要的:

template<class...Ts>
using variant_ref=std::variant<std::reference_wrapper<Ts>...>;
template<typename T>
using VectorOrSimple = std::variant<T, std::vector<T>>;
template<typename T>
using VectorOrSimpleRef = variant_ref<T, std::vector<T>>;
template<typename T>
using VectorOrSimpleConstRef = variant_ref<const T, const std::vector<T>>;

现在存储VectorOfSimpleConstRef<int>。(不是const&)。并将一个也在构造函数中。

还修改Print通过const&进行,以避免打印时不必要地复制std::vector