【问题标题】:Self-/circular reference in "using" statements“使用”语句中的自/循环引用
【发布时间】:2019-10-07 18:56:56
【问题描述】:

我尝试在我的程序中为动态变量定义一个变体类型,但我似乎无法让它存储一个将其作为类型返回的函数。

using Value = std::variant<Integer, Float, Function>;
using Function = std::function<Value()>;

这不会编译,因为 Function 需要在 Value 时定义,但 Function 也依赖于 Value。我尝试通过将Function 类型内联到变体模板列表中来解决此问题,但似乎using 语句无法引用自己或被前向声明。

到目前为止,我最好的解决方案是将Function 定义为一个结构,以便我可以转发声明它。这可行,但看起来很hacky,所以我想知道是否有更好的方法?

struct Function;
// define Value
struct Function : std::function<Value()> {};

为了澄清,std::function 被用作示例的一部分,因为我认为展示我正在尝试做的事情会更容易,而且我的 hacky 解决方案也需要它。如果可能的话,我更希望有一种方法也可以使用普通函数指针。

【问题讨论】:

  • 一个简单的函数指针也可以,我只是使用std::function,因为我认为它会使示例更简单,并且也适用于我的hacky解决方案
  • 老实说,我认为使用函数指针会更容易。但是正如您提到的 using 不能引用自己。所以它并没有真正的帮助。
  • 请注意,将 std::variant 与不完整类型一起使用是未定义行为。见std::variant and incomplete type: how does it work?。所以看起来你的解决方案是未定义的行为,即使在你尝试时它看起来有效,也可能实际上不起作用。
  • 你能把函数签名改成指向 Value 的指针吗?
  • 原计划是让函数返回一个std::optional&lt;Value&gt;,但为了简单起见,我在这里省略了它,但我不能使用指针返回类型。此外,我无法在其内部或之前引用 Value 声明。

标签: c++ forward-declaration


【解决方案1】:

这是行不通的,因为你实际上想要创建的是这样的:

std::variant&lt;Integer, Float, std::function&lt;std::variant&lt;Integer, Float, std::function&lt;std::variant&lt;Integer, Float, std::function&lt;std::variant&lt;Integer, Float, std::function&lt;std::variant&lt;Integer, Float, std::function&lt;std::variant&lt;Integer, Float, std::function&lt;std::variant&lt;Integer, Float, std::function&lt;std::variant&lt;Integer, Float, std::function&lt;std::variant&lt;Integer, Float, std::function&lt;std::variant&lt;Integer, Float, std::function&lt;std::variant&lt;Integer, Float, std::function&lt;...()&gt;&gt;()&gt;&gt;()&gt;&gt;()&gt;&gt;()&gt;&gt;()&gt;&gt;()&gt;&gt;()&gt;&gt;()&gt;&gt;()&gt;&gt;()&gt;&gt;;

所以基本上你在类型声明中有一个无限递归。

您需要通过使用一些没有递归定义的类型来解决这个问题,但不能像您建议的那样直接使用转发的struct,因为std::variant 只允许完整的类型。

您可以做的是前向声明您的struct,然后在您的std::variant 中使用您选择的容器/包装器/智能指针(例如std::unique_ptr&lt;Function&gt;):

struct Function;
using Value = std::variant<Integer, Float, std::unique_ptr<Function>>;
struct Function : std::function<Value()> {};

【讨论】:

  • @FrançoisAndrieux 是的,因为它只在内部保存一个指针。 std::make_unique 需要首先定义完整的类型,但 std::unique_ptr 本身不需要。
  • 它看起来与 pimpl 使用的非常相似,所以它应该可以正常工作,但 OP:s 原始版本与 struct Function; 的工作方式相同吗?
  • @TedLyngmo 不,不会。 std::variant 需要它的模板参数是完整的类型。在这种情况下,Function 不是一个完整的类型。 std::unique_ptr&lt;Function&gt; 是。
猜你喜欢
  • 2017-09-28
  • 2013-11-21
  • 1970-01-01
  • 1970-01-01
  • 2017-03-06
  • 2021-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多