C++ c++;通过引用存储的变量类成员

C++ c++;通过引用存储的变量类成员,c++,boost,c++17,variant,C++,Boost,C++17,Variant,我正在尝试std::variant。我将std::variant存储为类的成员。在下面的代码中,如果变量是按值存储的,则一切正常,但如果变量是按引用存储的,则一切都不起作用(对于向量和自定义对象也是如此)。为什么呢 #include <variant> #include <vector> #include <iostream> template<typename T> using VectorOrSimple = std::variant<

我正在尝试std::variant。我将std::variant存储为类的成员。在下面的代码中,如果变量是按值存储的,则一切正常,但如果变量是按引用存储的,则一切都不起作用(对于向量和自定义对象也是如此)。为什么呢

#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();
}
#包括
#包括
#包括
样板
使用VectorSimple=std::variant;
结构打印{

void操作符()(int v){std::cout它不起作用,因为此语句
a1(简单);
创建了一个临时变量对象

然后继续将所述临时文件绑定到const引用。但是,在
a1
的构造结束后,临时文件立即超出范围,留下一个悬空引用。显然,创建副本是可行的,因为它总是涉及使用有效副本

一个可能的解决方案(如果总是复制的性能让您担忧)是按值接受一个变量对象,然后将其移动到本地副本中,如下所示:

explicit A(VectorOrSimple<int> arg) : member(std::move(arg)) {
    print();
}
显式A(vectorSimple arg):成员(std::move(arg)){ 打印(); }

这将允许使用左值或右值调用构造函数。对于左值,您的
成员将通过移动源变量的副本来初始化,而对于
右值,源内容将只移动(最多)两次。

它不起作用,因为此语句
a1(简单);
创建一个临时变量对象

然后继续将所述临时文件绑定到const引用。但是,在
a1
的构造结束后,临时文件立即超出范围,留下一个悬空引用。显然,创建副本是可行的,因为它总是涉及使用有效副本

一个可能的解决方案(如果总是复制的性能让您担忧)是按值接受一个变量对象,然后将其移动到本地副本中,如下所示:

explicit A(VectorOrSimple<int> arg) : member(std::move(arg)) {
    print();
}
显式A(vectorSimple arg):成员(std::move(arg)){ 打印(); }

这将允许使用左值或右值调用构造函数。对于左值,将通过移动源变量的副本初始化
成员
,而对于
右值
则只移动源变量的内容(最多)两次。

变体是对象。它们包含一组类型中的一种,但不是这些类型中的一种

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

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

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>>;
模板
使用variant_ref=std::variant;
样板
使用VectorSimple=std::variant;
样板
使用VectorSimpleRef=变量_ref;
样板
使用VectorSimpleConstref=variant_ref;
现在存储
VectorOfSimpleConstRef
(而不是
const&
),并在构造函数中取一个


还可以修改
Print
以采用
const&
,以避免在打印时不必要地复制
std::vector

变体是对象。它们包含一组类型中的一种,但不是这些类型中的一种

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

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

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>>;
模板
使用variant_ref=std::variant;
样板
使用VectorSimple=std::variant;
样板
使用VectorSimpleRef=变量_ref;
样板
使用VectorSimpleConstref=variant_ref;
现在存储
VectorOfSimpleConstRef
(而不是
const&
),并在构造函数中取一个

同时修改
Print
以采用
const&
,以避免在打印时不必要地复制
std::vector