1

我的理解是std::variant不能直接保存引用。

但是,std::reference_wrapper是一种完全限定的类型,可以放入诸如 之类的东西std::vector中,并且由于可以制作引用包装器的向量,我想人们可以对std::variant.

以下(编辑得更简洁)代码在 gcc 中生成了大量错误:

#include <functional>
#include <variant>

class Foo;
class Baz;

template<typename T> struct CRef : std::reference_wrapper<const T> {
    CRef(const T &x) : std::reference_wrapper<const T>(x)
    {
    }
};    

template<typename... Args> struct Contains : public std::variant<CRef<Args>... > {
};

struct Foo : public Contains<Baz> {

    int getSize() const;
};

struct getSizeVisitor {

    template<typename T> int operator()(CRef<T> x) const
    {
        return sizeof(T);
    }
};

inline int Foo::getSize() const
{
    return std::visit(getSizeVisitor(), (*this));
}

struct Baz : public Foo {

};

CRef模板只是 std::reference_wrapper 到 const 引用的方便包装器,模板的Contains存在是为了帮助类了解基类在某些时候可能引用的所有端点子类。在上述情况下,我只是想要一个getSize()方法,它将返回变量中包含的实际类型的大小。 Baz,在这种情况下,是唯一的端点类,尽管实际上会有更多,并且它们没有公共基类,这就是为什么我需要一个变体,并且不能简单地使用基类并使用虚函数。

编译器生成的错误在这里可见:https ://godbolt.org/z/lcbPjB

所以,我想我可能正在做一些不允许的事情。

我的问题是,有没有办法做我正在尝试的事情?如果我的意图不清楚,我会提前道歉。如果在理解我要达到的目标时遇到问题,可以留下一些反馈,具体确定我需要提供哪些额外信息,我将努力遵守。

请记住,在实际用例中,端点类要复杂得多,并且除了 getSize() 之外还会有更多的函数,但我希望一旦我有一些适用于这个简单案例的东西,我应该能够概括和正确实现其他功能。

4

1 回答 1

1

这是同一问题的更短的再现:

int getSize(std::variant<int, char> var)
{
    return std::visit([](auto const& x){ return sizeof(x); },
        std::cref(var));
}

问题是,您试图将 a 传递reference_wrapperstd::visit... 但这违反了要求std::visit- 它需要实际std::variant的 s (在原始 OP 中,该对象甚至被更多地删除std::variant- 它是继承的类型的引用包装器从继承自的类型std::variant- 但距离variant无关紧要)。

您需要传入确切的变体。在我的简短示例中,这只是传递var而不是std::cref(var). 在 OP 中,这是*this正确variant<Ts...> const&的类型Ts...

于 2019-10-29T11:54:42.850 回答