Работа с циклической зависимостью в std::variant

#c #c 17 #circular-dependency #variant

#c #c 17 #циклическая зависимость #вариант

Вопрос:

Я пытаюсь справиться с циклической зависимостью в следующем сценарии:

У меня есть std:: variant, скажем:

 //types.h
using Types = std::variant<int, double, std::string, SomeClass>;
  

SomeClass — довольно простая вещь, содержащая несколько указателей, с некоторой шаблонной логикой:

 #someclass.h
class SomeClass {
    // few simple members (pointers and an integer)
    
    void use(Types arg); // note usage of Types here

    template<typename T, typename Ts...> // implicitly assuming T == Ts... == Types
    void use(T arg, Ts... tail) {
        use(arg);
        use(tail...);
    }

    SomeClass(const SomeClassamp;) = default; // works fine
};
  

Обычно я бы переадресовал SomeClass перед «использованием типов …», но это невозможно сделать, когда дело доходит до std:: variant. Я также на самом деле не нашел способа переадресовать директиву «using».

Одним из способов, который я нашел, было прямое объявление SomeClass и использование указателя на него в Types, но мне не нравится эта идея (SomeClass — действительно легкий объект с коротким сроком службы, я бы хотел сохранить его вне кучи).

Есть ли в C какой-либо другой способ (помимо указателей) решить эту проблему? У меня заканчиваются идеи.

Спасибо 🙂

Редактировать:

Проблема на самом деле появляется, только если я пытаюсь использовать типы до реального определения SomeClass, см. https://godbolt.org/z/4jzhEd

Комментарии:

1. С какой проблемой вы сталкиваетесь именно при использовании прямой передачи, объявленной SomeClass в std::variant ?

2. Не удается воспроизвести с помощью gcc . Компилируется просто отлично (после исправления очевидных опечаток и отсутствующих включений). Я не вижу проблемы с такого рода прямым объявлением. В чем бы ни заключалась ваша проблема, это должно быть что-то другое. Если вы используете другой компилятор, возможно, ошибка компилятора.

3. godbolt.org/z/vPj4eE

4. Мне удалось воспроизвести это godbolt.org/z/4jzhEd

5.Не имеет ничего общего с циклическими зависимостями или вариантами. Переместите определение SomeStruct после SomeClass . Вы просто не можете объявить член класса, тип которого не был определен. class B; class A { B b; }; class B {}; — это тоже не сработает по той же причине.

Ответ №1:

В приведенном вами живом примере все, что вам нужно для решения проблемы, — это определить SomeStruct после SomeClass .

Таким образом, ваш Types вариант больше не будет иметь неполных типов при SomeStruct определении. Другими словами, вот порядок:

 class SomeClass;

using Types = std::variant<..., SomeClass>;

class SomeClass {
   // ... // Types used here, but doesn't need to have all complete types
};

struct SomeStruct {
    Types value;
    // ...
};
  

Смотрите здесь живой пример.