Наследование оператора = и конструктора, но также добавление дополнительного назначения оболочки

У меня есть следующая структура:

struct Feedback : public TaggedUnion<Feedback1Idx, String>
{
    using TaggedUnion<Feedback1Idx, String>::TaggedUnion;
    using TaggedUnion<Feedback1Idx, String>::operator=;

    bool isError = false;
};

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

Feedback a = Feedback1Idx();
Feedback b = String();
Feedback c = Feedback();
Feedback d = b;

В приведенных выше примерах я хотел бы, чтобы a.isError было истинным, b.isError — истинным, но c.isError — ложным (и d.isError — истинным, потому что b.isError — истинным). Другими словами, каждый раз, когда используется унаследованный оператор =, я хотел бы, чтобы .isError был переключен на true.

Как я могу этого добиться? (без добавления конструктора/оператора присваивания для каждого параметра шаблона, который я добавляю в TaggedUnion<>)

Обратите внимание, что ни в одном из примеров не используется перегруженный оператор присваивания. Все они являются вызовами конструктора.

Some programmer dude 16.02.2023 13:46

Вы достигаете этого, определяя явный оператор присваивания вместо его наследования?

Sam Varshavchik 16.02.2023 13:53

@SamVarshavchik Действительно, однако в будущем я добавлю больше параметров шаблона в TaggedUnion<>, поэтому я бы хотел, чтобы это было автоматически, если это возможно. Я не против определения своего собственного оператора, это больше о том, «как мне определить его таким образом, чтобы он охватывал унаследованный оператор?» согласно названию; в противном случае это означало бы, что мне придется добавлять перегрузку каждый раз, когда я добавляю параметр в TaggedUnion<>

ZeroZ30o 16.02.2023 14:15

@Someprogrammerdude Это правда, однако возникают те же проблемы, но с конструкторами вместо операторов присваивания. В идеале я бы определил одинаковое поведение для них обоих.

ZeroZ30o 16.02.2023 14:19

Итак, ваш пользовательский оператор вызывает TaggedUnion::operator= явно?

Sam Varshavchik 16.02.2023 14:27

@SamVarshavchik Верно, но каков синтаксис для TaggedUnion::operator= и TaggedUnion::TaggedUnion в Feedback?

ZeroZ30o 16.02.2023 14:34
TaggedUnion<Feedback1Idx, String>::operator= и TaggedUnion<Feedback1Idx, String>::TaggedUnion, как показано в коде.
Sam Varshavchik 16.02.2023 14:36

@SamVarshavchik прав, но я не всегда хочу их вызывать, например, в конструкторе копирования Feedback::Feedback(const Feedback&other) я бы не стал это называть. Означает ли это, что я буду использовать шаблоны + специализация шаблонов? С тем, что вы предлагаете, мне пришлось бы определить Feedback::Feedback(const Feedback1Idx&other), а также Feedback::Feedback(const String&other), и продолжать добавлять больше с каждым добавляемым параметром шаблона.

ZeroZ30o 16.02.2023 14:37

Существуют различные методы решения этой проблемы с использованием шаблонов. Это был бы отдельный вопрос. На этот вопрос: нет, вы не можете определить такой оператор присваивания, С++ так не работает.

Sam Varshavchik 16.02.2023 14:39

@SamVarshavchik Это не отдельный вопрос. Вот этот вопрос. Это буквально то, о чем я прошу... Решение вышеуказанной проблемы, которое будет включать шаблоны (потому что я не хочу использовать виртуальные).

ZeroZ30o 16.02.2023 14:40

Вопрос относится к оператору присваивания, а не к какому-либо конструктору, как в вашем предыдущем комментарии. Операторы присваивания не являются конструкторами.

Sam Varshavchik 16.02.2023 14:42

@SamVarshavchik Именно из-за такого поведения людям не нравится stackoverflow. Люди, у которых есть проблема, очевидно, не определяют свою проблему с точностью учебника, потому что если бы у них была точность учебника, у них не было бы проблемы. Если вы не собираетесь отвечать на вопрос, это нормально. Но если вам это так нужно, я могу добавить «как я могу добиться этого БЕЗ ОБЪЯВЛЕНИЯ НОВОГО ОПЕРАТОРА КАЖДЫЙ РАЗ, КОГДА Я ДОБАВЛЯЮ ПАРАМЕТР», если это удовлетворяет ваше снобистское поведение. Кроме того, это относится к конструкторам так же, как и к операторам присваивания, поскольку они оба делают одно и то же, так что это не имеет значения.

ZeroZ30o 16.02.2023 14:45

Первоначальный вопрос заключался в следующем: «Каждый раз, когда используется унаследованный оператор =, я бы хотел, чтобы .isError был переключен на true». Я вполне доволен тем, что пусть все остальные судят, будет ли эта интерпретация разумно выведена из этого. Насколько я понимаю: есть ли где-нибудь волшебная палочка, от которой можно отказаться, чтобы унаследованный оператор = работал так? Ответ по-прежнему «нет», простой и короткий.

Sam Varshavchik 16.02.2023 14:52

@SamVarshavchik Снова. Я не отрицаю, что наиболее объективная интерпретация вопроса отличалась от того, что вы утверждаете. Я просто утверждаю, что вы пытаетесь максимально приблизиться к вопросу, не принимая во внимание, что люди могут не идеально выразить свою проблему с первой попытки. Пожалуйста, будьте более практичными, а не педантичными. Несмотря на это, я отредактировал вопрос сейчас, для вашего удовольствия.

ZeroZ30o 16.02.2023 14:55

К сожалению, альтернатива «быть как можно ближе к вопросу» — это пустая трата времени. Например, конструктор шаблона, который участвует в разрешении перегрузки, только если тип шаблона является одним из типов TaggedUnion, довольно прост. Но это работает только в том случае, если нет необходимости поддерживать неявные преобразования ни к одному из них. Требуется ли поддержка неявного преобразования? Только ты это знаешь. Итак, допустим, я трачу время на написание этого конструктора. Вы пробуете это и обнаруживаете, что теперь куча вещей не компилируется. Я потерял много времени.

Sam Varshavchik 16.02.2023 16:36

Хммм... Кажется, именно об этом были мои предыдущие комментарии: больше информации и пояснений. В любом случае, я с нетерпением жду возможности увидеть, каким оказалось ваше решение.

Sam Varshavchik 16.02.2023 17:48

Ну, как я объяснил: C++ не так прост. Вы не указали, должен ли перегруженный шаблон участвовать в разрешении перегрузки, если только параметр шаблона не может использоваться явно или неявно для создания одного из вариантов значений. Ваш ответ не ограничивает участие в разрешении перегрузок, что в конкретной ситуации приводит к сбоям компиляции. К сожалению, из-за отсутствия минимального воспроизводимого примера, который любой может вырезать/вставить и проверить, авторитетный ответ был бы невозможен без доступа к полному коду. Который есть только у тебя.

Sam Varshavchik 17.02.2023 00:50

Ну да, я сделал. До сих пор нет способа заставить унаследованную = перегрузку через директиву using работать так, как вы хотели, чтобы она работала. Во всяком случае, требуется определяемая пользователем перегрузка =. Как в вашем ответе. И никто тебя ни в чем не упрекал. Я просто заявил, что отказываюсь пытаться угадать и заполнить пробелы, делая необоснованные предположения.

Sam Varshavchik 17.02.2023 01:14
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
18
72
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я нашел простое решение:

struct Feedback : public TaggedUnion<Feedback1Idx, String>
{
    bool isError = false;

    Feedback() = default;

    Feedback(const Feedback& _other) = default;

    template<typename TYPE>
    Feedback(const TYPE& _other)
    : TaggedUnion<Feedback1Idx, String>(_other)
    {
        this->isError = true;
    }

    Feedback& operator=(const Feedback& _other) = default;
    
    template<typename TYPE>
    Feedback& operator=(const TYPE& _other)
    {
        this->isError = true;
        TaggedUnion<Feedback1Idx, String>::operator=(_other);
        return *this;
    }
};

Небольшое замечание: компилятор, вероятно, будет кричать на вас, если вы попытаетесь сделать Feedback a = int или какой-либо другой тип, не входящий в унаследованный тип.

В остальном должно быть все хорошо (немного проверял).

Другие вопросы по теме