Условно объявить переменную определенного типа

Вот чего я хочу достичь:

struct A { A(/* ... */) {} A(A const&) = delete; };
struct B { B(/* ... */) {} B(B const&) = delete; };

int main()
{
    static bool constexpr cond = false;

    [[maybe_unused]]
    A a(/* ... */);
    [[maybe_unused]]
    B b(/* ... */);

    std::conditional_t<cond, A, B> c = cond ? a : b;

    return 0;
}

Это не компилируется, поскольку "?" Оператор требует, чтобы оба типа были конвертируемы друг в друга. Что мне (очевидно) нужно, так это чтобы c было a или b в зависимости от того, является ли condtrue или false. Как я могу этого добиться?

auto& c = std::get<cond ? 0 : 1>(std::tie(a, b));Что-то в этом роде.
Igor Tandetnik 27.05.2024 22:40

Или auto c = [&]{ if constexpr (cond) return a; else return b; }();.

Evg 27.05.2024 22:42

Побочный вопрос: будут ли какие-либо плохие побочные эффекты, если тернарный оператор будет смягчен и позволит использовать неконвертируемые типы с обеих сторон?

Krzysiek Karbowiak 28.05.2024 10:04

@krzysiek — Он бы ужасно сломался, если бы cond не был constexpr. И оператор также является основой для std::common_type, который имеет условие «если такой тип существует».

BoP 28.05.2024 10:45

Есть еще одна проблема с вашим кодом. Поскольку вы удалили copy ctor как для A, так и для B, std::conditional_t<cond, A, B> c =... не может работать.

user12002570 28.05.2024 11:03

@user12002570 user12002570 Вы правы. Следует заменить ссылкой.

0xbadf00d 28.05.2024 13:20
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать 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
6
115
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Что-то, что технически работает, но не очень красиво:

auto& c = [&] -> auto& {
    if constexpr (cond) return a;
    else                return b;
}();

// rest of function ...

Это зависит от возможности if constexpr влиять на выведенный тип возвращаемого значения этого лямбда-выражения. Следовательно, оно также зависит от того, что cond является постоянным выражением.

Однако делать это придется довольно редко. Обычно вы пишете шаблон функции, который работает либо с A, либо с B, а затем передаете соответствующий объект.

// f could also be a separate function
auto f = [&](auto& c) {
    // rest of function ...
};

// this uses "if constexpr", but would work with a regular if statement too
if constexpr (cond) f(a);
else                f(b);

Дополнительный вопрос: вы не указали пустой список параметров в своей лямбде. Это действительно? Разве вместо этого не должно быть auto c = [&]() { ... }();? Также: как отмечалось в комментариях к вопросу, мне нужно вернуть ссылку. В итоге у меня получилось auto& c = [&]() -> auto& { ... }();. Без пустого списка параметров это больше не работает.

0xbadf00d 28.05.2024 13:27

@ 0xbadf00d это действительно с C++23. В C++20 вам понадобятся пустые круглые скобки.

Jan Schultke 28.05.2024 14:15

Вы можете создать свою собственную вспомогательную функцию, которая возвращает результат на основе постоянного выражения cond, как показано ниже.

Также обратите внимание, что в настоящее время в вашем коде есть другие ошибки, например, вы удалили векторы копирования A и B, а затем пытаетесь использовать инициализацию копирования, которая также не будет работать, как упомянуто в одном из комментариев.

template<bool cond, typename T, typename U>
auto makeT( const T &t, const U &u) requires(cond)
{
    return t; 
}  
template<bool cond, typename T, typename U>
auto makeT( const T &t, const U &u)
{
    return u; 
}
int main()
{
   //other code here
   
   std::conditional_t<cond, A, B> c = makeT<cond>(a,b);
}

Демо

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