Вот чего я хочу достичь:
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 = [&]{ if constexpr (cond) return a; else return b; }();.
Побочный вопрос: будут ли какие-либо плохие побочные эффекты, если тернарный оператор будет смягчен и позволит использовать неконвертируемые типы с обеих сторон?
@krzysiek — Он бы ужасно сломался, если бы cond не был constexpr. И оператор также является основой для std::common_type, который имеет условие «если такой тип существует».
Есть еще одна проблема с вашим кодом. Поскольку вы удалили copy ctor как для A, так и для B, std::conditional_t<cond, A, B> c =... не может работать.
@user12002570 user12002570 Вы правы. Следует заменить ссылкой.





Что-то, что технически работает, но не очень красиво:
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 это действительно с C++23. В C++20 вам понадобятся пустые круглые скобки.
Вы можете создать свою собственную вспомогательную функцию, которая возвращает результат на основе постоянного выражения 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);
}
auto& c = std::get<cond ? 0 : 1>(std::tie(a, b));Что-то в этом роде.