在 std::variant 中使用不完整类型
Posted
技术标签:
【中文标题】在 std::variant 中使用不完整类型【英文标题】:Use of incomplete types with std::variant 【发布时间】:2021-12-28 20:32:17 【问题描述】:假设我有下一个代码,用于简单地存储类型为A
、B
或C
的对象的引用/指针。我实际上不需要完整的类型。
现在我有以下解决方案,我需要很多 #include 膨胀。
标题:
using MyVariant = std::variant<class A, class B, class C, ...>;
class Holder
public:
Holder(MyVariant &&TheValue);
const MyVariant &GetValue();
private:
std::unique_ptr<MyVariant> Value;
;
源文件:
#include "A.hpp"
#include "B.hpp"
#include "C.hpp"
Holder::Holder(MyVariant &&TheValue)
: Value(std::make_unique<MyVariant>(std::move(TheValue))
const MyVariant &Holder::GetValue return Value;
如何在没有所有实例化类型的情况下实现与 std::variant 模板参数/动态内存分配/动态多态性相同的语义?
【问题讨论】:
如果你只是想持有指针,那为什么不std::variant<A*, B*, C*>
呢? (或std::unique_ptr
等效项)。
我想避免很多new
调用,所以我不能在堆栈上分配对象并将指针传递给它。而不是这个,我通常希望自己持有一个值。
在您当前的解决方案中,为什么使用std::unique_ptr<MyVariant> Value;
而不是MyVariant Value;
?即使对于自动 Holder
实例,这也会将变体放入堆栈中。
@385i 如果您希望std::variant
实际保存没有间接的类型,那么它们在逻辑上必须是完整的,因为std::variant
需要知道为它们保留多少内存。
@385i variant
不能用于不完整的类型,原因相同,没有任何解决方法可以满足您的所有要求。您希望对象就地存储值(没有外部存储器)。为此,对象必须至少与它可以容纳的最大类型一样大。为此,它必须知道它可以容纳的每种类型的大小。为此,每种类型都必须是完整的(您无法获得不完整类型的大小),这与您对类型不完整的要求相矛盾。
【参考方案1】:
正如其他人指出的那样,规格似乎有点矛盾。
我只能想到可变模板参数,以实现不必为Holder
类指定所有可能的类。
Example
#include <iostream>
#include <memory>
#include <variant>
// h
template<typename ...T>
class Holder
using variant = std::variant<T...>;
public:
Holder(variant &&TheValue)
:Value(std::make_unique<variant>(std::move(TheValue)))
;
template<typename TARGET>
const TARGET &GetValue() const
return std::get<TARGET>(*Value);
;
private:
std::unique_ptr<variant> Value;
;
// main.cpp testing
int main()
auto a = Holder<int, float>(5);
const auto v = a.GetValue<int>();
std::cout << "holding int: " << v << std::endl;
a = Holder<int, float>(5.5f);
const auto v2 = a.GetValue<float>();
std::cout << "holding float: " << v2 << std::endl;
我认为在这一点上它看起来像是一个相当多余的类。
【讨论】:
以上是关于在 std::variant 中使用不完整类型的主要内容,如果未能解决你的问题,请参考以下文章
使用类作为数据类型时如何在 std::variant 中存储值?
std::visit 无法推断 std::variant 的类型
C++17,制作一个使用依赖于模板参数的 std::variant 的可变参数模板?
std::variant 是不是提供类似于 boost::variant<>::types 的功能?