标准变体和前向声明

std variant and forward declarations

据我了解,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 模板只是对 const 引用的 std::reference_wrapper 的方便包装,Contains 模板的存在是为了帮助 class 意识到base class 在某些时候可能引用的所有端点 subclasses。在上面的例子中,我只是想要一个 getSize() 方法,它将 return 变体中包含的实际类型的大小。 Baz,在这种情况下,是唯一的端点 class,尽管在实践中会有更多,并且它们没有共同的基础 class,这就是为什么我需要一个变体,并且不能简单地使用基 class 并使用虚函数。

此处可见编译器生成的错误:https://godbolt.org/z/lcbPjB

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

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

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

这是对同一期的更短的复制:

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

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

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

,将 *this 向下转换为 variant<Ts...> const&