标准变体和前向声明
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::variant
s(在原始 OP 中,对象甚至从 std::variant
中删除 - 它是一个类型的引用包装器,该类型继承自 std::variant
- 但与 variant
的距离无关紧要)。
您需要传入确切的变体。在我的简短示例中,这只是传递 var
而不是 std::cref(var)
。在 OP 中,对于正确的类型 Ts...
,将 *this
向下转换为 variant<Ts...> const&
据我了解,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::variant
s(在原始 OP 中,对象甚至从 std::variant
中删除 - 它是一个类型的引用包装器,该类型继承自 std::variant
- 但与 variant
的距离无关紧要)。
您需要传入确切的变体。在我的简短示例中,这只是传递 var
而不是 std::cref(var)
。在 OP 中,对于正确的类型 Ts...
*this
向下转换为 variant<Ts...> const&