Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Self-/circular reference in "using" statements

I've tried defining a variant type for dynamic variables in my program, but I can't seem to be able to make it store a function that returns it as a type.

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

This won't compile because Function needs to be defined at the time Value is, but Function depends on Value too. I've tried fixing this by inlining the Function type into the variant template list but it seems that using statements can't reference themselves or be forward declared.

My best solution so far has been defining Function as a struct so I can forward declare it. This works, but seems so hacky, so I'm wondering if there's a better way?

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

To clarify, std::function was used as part of the example because I thought it would be easier to show what I was trying to do and it also was needed for my hacky solution. I'd prefer a way to have this working with plain function pointers too, if possible.

like image 847
Rerumu Avatar asked Oct 07 '19 18:10

Rerumu


People also ask

What is a circular reference provide your own example?

A circular reference is a type of pop-up or warning displayed by Excel that we are using a circular reference in our formula and the calculation might be incorrect. For example, in cell A1, if we write a formula =A1*2, this is a circular reference as inside the cell A1 we used the cell reference to A1 itself.

How do you use a circular reference?

Go to the Formulas tab, click the arrow next to Error Checking, and point to Circular References The last entered circular reference is displayed there. Click on the cell listed under Circular References, and Excel will bring you exactly to that cell.

How does self referencing if work?

Self referencing IF statements allow you to present the results of multiple scenarios regardless of the individual scenario being run in the model. Financial analysts use scenarios in financial models to establish how a model's output will change based on various inputs changing.


1 Answers

This can't work, because what you are essentially trying to create is this:

std::variant<Integer, Float, std::function<std::variant<Integer, Float, std::function<std::variant<Integer, Float, std::function<std::variant<Integer, Float, std::function<std::variant<Integer, Float, std::function<std::variant<Integer, Float, std::function<std::variant<Integer, Float, std::function<std::variant<Integer, Float, std::function<std::variant<Integer, Float, std::function<std::variant<Integer, Float, std::function<std::variant<Integer, Float, std::function<...()>>()>>()>>()>>()>>()>>()>>()>>()>>()>>()>>;

So basically you have an infinite recursion within the type declarations.

You need to work around this by using some type that doesn't have a recursive definition, but using a forwarded struct directly like you suggest is not an option, because std::variant only allows complete types.

What you could do is forward declare your struct, and then use a container/wrapper/smart pointer of your choice (e.g. std::unique_ptr<Function>) in your std::variant:

struct Function;
using Value = std::variant<Integer, Float, std::unique_ptr<Function>>;
struct Function : std::function<Value()> {};
like image 157
Max Vollmer Avatar answered Sep 17 '22 17:09

Max Vollmer