static_assert в catch секции
От: Videoman Россия https://hts.tv/
Дата: 21.12.24 12:25
Оценка:
Как известно в С++20 подвезли возможность использовать try catch блоки внутри constexpr выражений. Стало удобно, но появилась следующая проблема:

Есть функция func1(), которая без проблем работает в constexpr режиме и есть внешняя функция func2(), которая никогда не должна выкидывать исключения, которая вызывает внутри себя первую, типа такого:
template<typename...>
inline constexpr bool always_false = false;

template<typename type_t>
constexpr int func2() noexcept
{
  try {
    return func1();
  } catch (...) {
    static_assert(always_false<type_t>, "error!");
    return 0;
  }
}

Так вот, стандартный подход с always_false тут не прокатывает и static_assert срабатывает всегда, а мне нужно что бы он срабатывал только если возникло исключение. Как такое можно организовать?
Отредактировано 21.12.2024 13:19 Videoman . Предыдущая версия .
Re: static_assert в catch секции
От: rg45 СССР  
Дата: 21.12.24 14:44
Оценка: 78 (2)
Здравствуйте, Videoman, Вы писали:

V>Как известно в С++20 подвезли возможность использовать try catch блоки внутри constexpr выражений. Стало удобно, но появилась следующая проблема:


V>Есть функция func1(), которая без проблем работает в constexpr режиме и есть внешняя функция func2(), которая никогда не должна выкидывать исключения, которая вызывает внутри себя первую, типа такого:
V>template<typename...>
V>inline constexpr bool always_false = false;

V>template<typename type_t>
V>constexpr int func2() noexcept
V>{
V>  try {
V>    return func1();
V>  } catch (...) {
V>    static_assert(always_false<type_t>, "error!");
V>    return 0;
V>  }
V>}
V>

V>Так вот, стандартный подход с always_false тут не прокатывает и static_assert срабатывает всегда, а мне нужно что бы он срабатывал только если возникло исключение. Как такое можно организовать?

Ну да, для того, чтобы это сработало, компилятор должен исключить этот static_assert из компиляции. А у него для этого нет поводов. Тут нужно как-то адаптировать дизайн. Например, обернуть в constexpr if:

http://coliru.stacked-crooked.com/a/d21b3db809532a31

#include <exception>
#include <utility>

template<typename...>
inline constexpr bool always_false = false;

constexpr int func1()
{
    return 1;
}

template<typename type_t>
constexpr int func2() noexcept
{
  constexpr auto call_func1 = []() -> std::pair<int, bool> {
    try {
      return {func1(), true};
    } catch (...) {
      return {};
    }
  };    
  constexpr auto res = call_func1();

  if constexpr (res.second) return res.first;
  else static_assert(always_false<type_t>, "error!");
}

int main()
{
  return func2<int>();
}
--
Справедливость выше закона. А человечность выше справедливости.
Re: static_assert в catch секции
От: rg45 СССР  
Дата: 21.12.24 14:49
Оценка:
Здравствуйте, Videoman, Вы писали:

V>Как известно в С++20 подвезли возможность использовать try catch блоки внутри constexpr выражений. Стало удобно, но появилась следующая проблема:


V>Есть функция func1(), которая без проблем работает в constexpr режиме и есть внешняя функция func2(), которая никогда не должна выкидывать исключения, которая вызывает внутри себя первую, типа такого:
V>template<typename...>
V>inline constexpr bool always_false = false;

V>template<typename type_t>
V>constexpr int func2() noexcept
V>{
V>  try {
V>    return func1();
V>  } catch (...) {
V>    static_assert(always_false<type_t>, "error!");
V>    return 0;
V>  }
V>}
V>

V>Так вот, стандартный подход с always_false тут не прокатывает и static_assert срабатывает всегда, а мне нужно что бы он срабатывал только если возникло исключение. Как такое можно организовать?

Интуиция подсказывает, что здесь можно как-то с пользой использовать атрибут assume, но что-то не соображу, как именно.
--
Справедливость выше закона. А человечность выше справедливости.
Re[2]: static_assert в catch секции
От: Videoman Россия https://hts.tv/
Дата: 21.12.24 15:03
Оценка:
Здравствуйте, rg45, Вы писали:

R>...


Делал именно таким методом, но было подумал, что занимаюсь извращением и как-то сложно получается. Вот решил спросить у более опытных коллег. Интересно имменно в рамках 20-го стандарта.
Тут масса вариавнов: можно через pair, можно через option, но в любом случае, приходится городить массу кода для преобразования типов исключений в сообщения об ошибках.
Отредактировано 21.12.2024 15:06 Videoman . Предыдущая версия .
Re[3]: static_assert в catch секции
От: rg45 СССР  
Дата: 21.12.24 15:05
Оценка: :))
Здравствуйте, Videoman, Вы писали:

V>Делал именно таким методом, но было подумал, что занимаюсь извращением и как-то сложно получается. Вот решил спросить у более опытных коллег. Интересно имменно в рамках 20-го стандарта.


Ну, ждём более опытных
--
Справедливость выше закона. А человечность выше справедливости.
Re: static_assert в catch секции
От: so5team https://stiffstream.com
Дата: 22.12.24 05:45
Оценка: +2
Здравствуйте, Videoman, Вы писали:

V>Как известно в С++20 подвезли возможность использовать try catch блоки внутри constexpr выражений.


А как в рамках C++20 (и даже C++23) бросить исключение в compile-time?
Re[2]: static_assert в catch секции
От: Videoman Россия https://hts.tv/
Дата: 22.12.24 13:04
Оценка:
Здравствуйте, so5team, Вы писали:

S>А как в рамках C++20 (и даже C++23) бросить исключение в compile-time?


Также как с выделением памяти. Если весь процесс остается внутри и все сайд эффекты compile-time, но всё работает. Сама внешняя функция noexcept, наружу ничего не летит.
Re[3]: static_assert в catch секции
От: so5team https://stiffstream.com
Дата: 22.12.24 13:18
Оценка: +1
Здравствуйте, Videoman, Вы писали:

S>>А как в рамках C++20 (и даже C++23) бросить исключение в compile-time?


V>Также как с выделением памяти. Если весь процесс остается внутри и все сайд эффекты compile-time, но всё работает. Сама внешняя функция noexcept, наружу ничего не летит.


Простите, понятнее не стало. В C++20 разве можно написать constexpr-функцию, которая бросает исключение в compile-time?

А если нет, то зачем защищаться от исключений, которые в compiler-time могут возникнуть, если возникнуть им неоткуда?
Re: static_assert в catch секции
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 22.12.24 14:10
Оценка: +1
Здравствуйте, Videoman, Вы писали:

V>Как известно в С++20 подвезли возможность использовать try catch блоки внутри constexpr выражений. Стало удобно


Если не секрет, что именно стало удобно с появлением этой возможности?
Re[4]: static_assert в catch секции
От: Videoman Россия https://hts.tv/
Дата: 22.12.24 20:11
Оценка:
Здравствуйте, so5team, Вы писали:

Ну запутали, так запутали!!!
Re[5]: static_assert в catch секции
От: so5team https://stiffstream.com
Дата: 23.12.24 03:49
Оценка: +1
Здравствуйте, Videoman, Вы писали:

V>Здравствуйте, so5team, Вы писали:


V>Ну запутали, так запутали!!!


Простите, не понял, что означает ваш ответ с фейспалмом.

И получается какая-то странная ситуация: вы задаете вопрос, я пытаюсь набросать решение и сталкиваюсь с тем, что не могу его протестировать, т.к. в C++20 (C++23) нет возможности бросить исключение из constexpr-функции в компайл-тайм. Понимаю, что чего-то не понимаю в постановке задачи, задаю уточняющие вопросы, а в ответ фейспалм.

Абыдна, да.
Re: static_assert в catch секции
От: Chorkov Россия  
Дата: 23.12.24 09:05
Оценка: 15 (2)
Здравствуйте, Videoman, Вы писали:

V>Как известно в С++20 подвезли возможность использовать try catch блоки внутри constexpr выражений. Стало удобно, но появилась следующая проблема:


V>Есть функция func1(), которая без проблем работает в constexpr режиме и есть внешняя функция func2(), которая никогда не должна выкидывать исключения, которая вызывает внутри себя первую, типа такого:
V>template<typename...>
V>inline constexpr bool always_false = false;

V>template<typename type_t>
V>constexpr int func2() noexcept
V>{
V>  try {
V>    return func1();
V>  } catch (...) {
V>    static_assert(always_false<type_t>, "error!");
V>    return 0;
V>  }
V>}
V>

V>Так вот, стандартный подход с always_false тут не прокатывает и static_assert срабатывает всегда, а мне нужно что бы он срабатывал только если возникло исключение. Как такое можно организовать?

Если func1 помечена как noexcept, то достаточно проверить это:
https://en.cppreference.com/w/cpp/language/noexcept
template<typename type_t>
constexpr int func2() noexcept
{
  static_assert( noexcept( func1() ) );
  return func1();
}



Или, если не помечено, то можно сделать проверку, использця идею rg45:
template<auto Func>
constexpr bool is_constexpr_noexcept() noexcept
{
    try {
      Func();
      return true;
    } catch (...) {
      return false;
    }
}

template<typename type_t>
constexpr int func2() noexcept
{
  static_assert( is_constexpr_noexcept< func1 >() ) ;
  return func1();
}


Правда, тут есть подложенные грабли: в C++23 func1 может менять поведение, в процессе compile-time вычислений:
#include <exception>
#include <exception>
#include <utility>

constexpr int func1()
{
    if consteval
    {
        return 1;
    }
    else
    {
        throw 42;
    }
}

template<auto Func>
constexpr bool is_constexpr_noexcept() noexcept
{
    try {
      Func();
      return  true;
    } catch (...) {
      return false;
    }
}
template<typename type_t>
constexpr int func2() noexcept
{
  static_assert( is_constexpr_noexcept< func1 >() ) ;
  constexpr auto result = func1();
  return result;
}

int main()
{
  return func2<int>(); // throw 42, если не сделать constexpr auto result в func2;
}
Re[6]: static_assert в catch секции
От: Videoman Россия https://hts.tv/
Дата: 23.12.24 09:18
Оценка:
Здравствуйте, so5team, Вы писали:

S>Простите, не понял, что означает ваш ответ с фейспалмом.


Да я не вам вообще, я на ситуацию в общем.
Я только погружаюсь в 20-й стандарт. Просто задал вопрос, а вы мне в ответ тоже вопрос, да еще как-то неуверенно, может/не может кидать исключения
Из-за того, что не понятно сработают на этапе компиляции constexpr выражения или нет, у меня возникла путаница в коде в котором вперемешку constexpr/не constexpr реализация через std::is_constant_evaluated.
Теперь мне понятно как это работает:
в runtime версии возможно throw, а в constexpr — нет, но просто синтаксис try блоков теперь не отпугивает компилятор.

После паузы я и написал — как все запутано в стандарте.
Re[2]: static_assert в catch секции
От: Videoman Россия https://hts.tv/
Дата: 23.12.24 09:22
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Если не секрет, что именно стало удобно с появлением этой возможности?


Писать в одной функции две ветки кода, одна для вычисления на уровне компиляции, а другая в run-time.
Re[7]: static_assert в catch секции
От: so5team https://stiffstream.com
Дата: 23.12.24 09:29
Оценка:
Здравствуйте, Videoman, Вы писали:

V>Я только погружаюсь в 20-й стандарт. Просто задал вопрос, а вы мне в ответ тоже вопрос, да еще как-то неуверенно, может/не может кидать исключения


У меня у самого путаница в стандартах: в каких-то разрешили динамическую память в виде std::string (вроде бы в C++23), в каких-то вроде как и выброс исключений в compile-time разрешили (емнип, в C++26).

Поэтому если смотреть на самые свежие стандарты, то вроде как там можно столкнуться с проблемой, про которую вы спрашиваете. И может быть вы хотите сейчас, уже в рамках C++20 защититься о того, что добавили в С++26. Но проверить гипотетическое решение в рамках C++20 (и вроде бы даже в рамках C++23) не представляется возможным, т.к. в этих стандартах constexpr-функции не бросают исключений.

V>После паузы я и написал — как все запутано в стандарте.


Да не, вроде бы в конкретном стандарте все более-менее. А вот если пытаться прикидывать на перспективу, на тот же C++26, который когда-нибудь компиляторами будет поддержан, то да, становится запутанно.
Re[8]: static_assert в catch секции
От: Videoman Россия https://hts.tv/
Дата: 23.12.24 09:44
Оценка:
Здравствуйте, so5team, Вы писали:

S>Поэтому если смотреть на самые свежие стандарты, то вроде как там можно столкнуться с проблемой, про которую вы спрашиваете. И может быть вы хотите сейчас, уже в рамках C++20 защититься о того, что добавили в С++26. Но проверить гипотетическое решение в рамках C++20 (и вроде бы даже в рамках C++23) не представляется возможным, т.к. в этих стандартах constexpr-функции не бросают исключений.


Не, так далеко я не заглядываю. Действуем потихоньку, сначала 20-й, дальше посмотрим.
Для меня главные две фишки С++20 сейчас, это std::is_constant_evaluated() и concept`ы. Вот и возникают некоторые вопросы, возможно уже всем понятные, по мере переползания на новый стандарт.
А ваши контор-вопросы меня просто в тупик поставили и пришлось самому погружаться в тему и разбираться, поэтому и не смог ничего внятного ответить.
Re[9]: static_assert в catch секции
От: so5team https://stiffstream.com
Дата: 23.12.24 09:46
Оценка:
Здравствуйте, Videoman, Вы писали:

V>А ваши контор-вопросы меня просто в тупик поставили и пришлось самому погружаться в тему и разбираться, поэтому и не смог ничего внятного ответить.


Значит все пошло на пользу
Re[3]: static_assert в catch секции
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 23.12.24 11:26
Оценка:
Здравствуйте, Videoman, Вы писали:

V>Писать в одной функции две ветки кода, одна для вычисления на уровне компиляции, а другая в run-time.


Нынче считается, что это способствует ясности изложения кода?
Re[3]: static_assert в catch секции
От: rg45 СССР  
Дата: 23.12.24 11:39
Оценка:
Здравствуйте, Videoman, Вы писали:

V>Писать в одной функции две ветки кода, одна для вычисления на уровне компиляции, а другая в run-time.


Я вот тоже не очень понимаю, какую пользу можно извлечь из возможности писать try-catch в constexpr функции. Что может бросить исключение из того, что допустимо использовать внутри функции? А если ничего не может, то зачем тогда try-catch?
--
Справедливость выше закона. А человечность выше справедливости.
Re[4]: static_assert в catch секции
От: so5team https://stiffstream.com
Дата: 23.12.24 11:45
Оценка:
Здравствуйте, rg45, Вы писали:

V>>Писать в одной функции две ветки кода, одна для вычисления на уровне компиляции, а другая в run-time.


R>Я вот тоже не очень понимаю, какую пользу можно извлечь из возможности писать try-catch в constexpr функции. Что может бросить исключение из того, что допустимо использовать внутри функции? А если ничего не может, то зачем тогда try-catch?


А возможен ли такой сценарий: у человека была обычная функция, которая содержала внутри себя try-catch, но которую хотелось иметь еще и в виде constexpr, но раньше нельзя было это делать, т.к. там были try-catch.

Грубо говоря, было:

template<typename T>
int f() {
  try {
    return T::some_func();
  }
  catch(...) {
    // Ну не шмогли, ну и ладно.
    return 0;
  }
}


Теперь такая возможность появляется (т.е. функцию f из примера выше можно объявить constexpr) но не хочется "проглатывать" исключения, если они происходят в compile-time.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.