Я пытаюсь использовать if constexpr следующим образом:
template<template <typename First, typename Second> class Trait,
typename First, typename Second, typename... Rest>
constexpr bool binaryTraitAre_impl()
{
if constexpr (sizeof... (Rest) == 0)
{
return Trait<First, Second>{}();
}
return Trait<First, Second>{}() and binaryTraitAre_impl<Trait, Rest...>();
}
Пример использования:
static_assert(binaryTraitAre_impl<std::is_convertible,
int, int&,
int*, void*>());
Но это не скомпилировать
error: no matching function for call to 'binaryTraitAre_impl'
return Trait<First, Second>{}() and binaryTraitAre_impl<Trait, Rest...>();
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
prog.cc: In instantiation of 'constexpr bool binaryTraitAre_impl() [with Trait = std::is_convertible; First = int*; Second = void*; Rest = {}]':
prog.cc:9:80: required from 'constexpr bool binaryTraitAre_impl() [with Trait = std::is_convertible; First = int; Second = int&; Rest = {int*, void*}]'
prog.cc:15:83: required from here
prog.cc:9:80: error: no matching function for call to 'binaryTraitAre_impl<template<class _From, class _To> struct std::is_convertible>()'
9 | return Trait<First, Second>{}() and binaryTraitAre_impl<Trait, Rest...>();
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
prog.cc:3:17: note: candidate: 'template<template<class First, class Second> class Trait, class First, class Second, class ... Rest> constexpr bool binaryTraitAre_impl()'
3 | constexpr bool binaryTraitAre_impl()
| ^~~~~~~~~~~~~~~~~~~
prog.cc:3:17: note: template argument deduction/substitution failed:
prog.cc:9:80: note: couldn't deduce template parameter 'First'
9 | return Trait<First, Second>{}() and binaryTraitAre_impl<Trait, Rest...>();
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
Но я обнаружил, что ошибка исчезает после добавления else:
template<template <typename First, typename Second> class Trait,
typename First, typename Second, typename... Rest>
constexpr bool binaryTraitAre_impl()
{
if constexpr (sizeof... (Rest) == 0)
{
return Trait<First, Second>{}();
}
else
{
return Trait<First, Second>{}() and binaryTraitAre_impl<Trait, Rest...>();
}
}
Что случилось? Почему в этом случае компилятор не может определить else?
@Rakete не смог найти его на странице тега if-constexpr (хорошо, я просмотрел только первую страницу). Если найдешь, удалю свой ответ.
@MatthieuBrucher то же самое.
Если у него есть официальная идиома, он будет более дружественным к SEO
@ Rakete1111 Да, мне кажется, что я уже встречал подобный вопрос раньше, но мне всегда трудно найти хорошие обманы (вот почему я в конечном итоге прибегаю к тому, чтобы отдавать предпочтение обычным обманам).
Обратите внимание, что ваша реализация неверна - это даст мне true для binaryTraitAre_impl<is_same, int, double>() (это второстепенно для вопроса в целом)
@ Барри, спасибо! Позже я добавлю больше тестовых примеров локально.
@Barry Я, наверное, сохраню это как ссылку для таких дубликатов.





Это отрывок из cppreference на constexpr if:
Constexpr If The statement that begins with if constexpr is known as the constexpr if statement.
In a constexpr if statement, the value of condition must be a contextually converted constant expression of type bool. If the value is true, then statement-false is discarded (if present), otherwise, statement-true is discarded.
Понятно, что отбрасывается только одна из двух ветвей. В вашем случае код виновника не может быть отброшен, потому что он находится вне пункта else.
if constexpr, когда предложение истинно, не исключает код вне соответствующего блока else.
Вы можете расширить C++ для этого, но это быстро становится проблемой. Очевидны только самые тривиальные случаи, и указывать, что это за тривиальные случаи, очень сложно. Я имею в виду, вы покрываете:
if constexpr( blah ){
if (true) return 7;
}
? Как насчет
if constexpr( blah ){
if (blah) return 7;
else exit(-1);
}
? Или
if constexpr( blah ){
if (blah) return 7;
else return false;
}
или
if constexpr( blah ){
if (blah) goto foo;
return false;
foo: return true;
}
или как насчет:
if constexpr( blah ){
std::size_t count = 0;
while (foo != 1 && (++count < (std::size_t)-1))
switch (foo%2) {
case 1: foo = 3*foo+1;
case 0: foo = foo/2;
}
}
if (count < (std::size_t)-1) return true;
}
? Я могу привести почти континуум случаев, которые более или менее «очевидны» в том, что они никогда не вернутся. А расплата? Отсутствие else. Много проблем, мало пользы.
У компиляторов есть специальные правила для обнаружения недоступного кода и т.п. Их не нужно указывать так формально, как в стандарте, и они могут отличаться от одного компилятора к другому.
Между тем стандарт должен быть одинаковым для всех компиляторов. И правила в отношении того, что удаляется, а что нет, должны быть идентичными.
Стандарт применяет простое правило; блоки if и else - единственные кандидаты на удаление.
Так что стандарт этого не делает. Если вы хотите, чтобы код был исключен, поместите его в блок if constexpr или elseif constexpr. Ресурсы по языковому развитию лучше тратить на вещи, которые приносят больше пользы и менее болезненны.
А вот и обязательная ссылка на проблему остановки.
Есть ли обман на такие вопросы? Кажется, что
if constexpr- это нелогичная функция, которую многие люди ошибаются. Я почти уверен, что уже видел такой вопрос ...