在 std::variant 中使用不完整类型

Posted

技术标签:

【中文标题】在 std::variant 中使用不完整类型【英文标题】:Use of incomplete types with std::variant 【发布时间】:2021-12-28 20:32:17 【问题描述】:

假设我有下一个代码,用于简单地存储类型为ABC 的对象的引用/指针。我实际上不需要完整的类型。

现在我有以下解决方案,我需要很多 #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&lt;A*, B*, C*&gt;呢? (或std::unique_ptr 等效项)。 我想避免很多new 调用,所以我不能在堆栈上分配对象并将指针传递给它。而不是这个,我通常希望自己持有一个值。 在您当前的解决方案中,为什么使用std::unique_ptr&lt;MyVariant&gt; 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 的功能?

对 std::variant 中保存的类型调用 << 运算符?

如何在编译时捕获 std::variant 持有错误类型?