std变体和正向声明

std variant and forward declarations

本文关键字:声明 std      更新时间:2023-10-16

我的理解是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模板的存在是为了帮助类了解基类在某个时刻可能引用的所有端点子类。在上述情况下,我只是想要一个getSize()方法,它将返回变体中包含的实际类型的大小。在这种情况下,Baz是唯一的端点类,尽管在实践中会有更多,而且它们没有公共基类,这就是为什么我需要一个变体,并且不能简单地使用基类和使用虚拟函数。

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

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

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

请记住,在实际的用例中,端点类要复杂得多,除了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中,这是将*this向下转换为variant<Ts...> const&以获得正确的类型Ts...