Может ли добавление constexpr изменить поведение?

Учитывая две программы, где единственным отличием в исходном коде является наличие или отсутствие одного constexprВозможно ли, что смысл программы меняется?

Другими словами, если бы была опция компилятора, попросите компилятор действительно постараться сделать вывод constexpr где это возможно, нарушит ли он существующий стандартный код и / или изменит его значение плохими способами?

Представьте себе, что вы имеете дело с кодовой базой, в которой первоначальный разработчик забыл включить constexpr в местах, где это было возможно, возможно, код, написанный до C++11. Было бы здорово, если бы компилятор выводил constexpr чтобы помочь вам продолжить свою работу. Конечно, возможно, он также должен предупреждать о том, что каждый раз, когда он делает этот вывод, поощряя вас явно добавлять constexpr потом. Но это все равно будет полезно. Я беспокоюсь, что это может сломать вещи?

Пока что я могу думать только о том, что constexpr функции неявно inline и могут быть ситуации, когда добавление inline может изменить вещи плохими способами; например, если вы нарушаете правило одного определения.

2 ответа

Решение

Есть простой трюк:

template<int n>struct i{};
int foo(int){return 0;}
constexpr int foo(char){return 'a';}

template<class T=int, T x=1,i<foo(x)>* =nullptr>
bool bar(){return true;}
template<class T=int, T x=1,class...Ts>
bool bar(Ts...){return false;}

если int foo(int) является constexpr, другая перегрузка bar выбран по умолчанию.

При выполнении другого кода может произойти любое изменение поведения.

живой пример (просто поменяй который #define X закомментировано).


Дизайн примера:

char Перегрузка предотвращает неправильное формирование вышеуказанного кода, диагностика не требуется, так как все шаблоны должны иметь действительную специализацию. foo<char> поставляет это. На практике его существование не требуется: ADL может найти foo издалека перегружен на some_type*затем пройти some_type* как T, Это означает, что ни один модуль компиляции не может доказать, что код был неверно сформирован.

Ts... делает это bar перегрузка менее предпочтительна. Так что, если первый совпадает, нет никакой двусмысленности. Только если первый не соответствует (из-за SFINAE, вызванного foo(x) Не существует constexpr) вызывается ли вторая перегрузка (или если, скажем, кто-то передал ей аргументы).

Учитывая две программы, в которых единственным отличием в исходном коде является наличие или отсутствие одного constexpr, возможно ли, что значение программы изменится?

Да, это по крайней мере верно для функций constexpr. Это причина, по которой реализациям не разрешается выбирать, какие стандартные функции помечены как constexpr, основная проблема заключается в том, что пользователи могут наблюдать различные варианты поведения через SFINAE. Это задокументировано в выпуске 2013 LWG: есть ли у разработчиков библиотек возможность добавить constexpr? который говорит (выделение мое):

Некоторая обеспокоенность была выражена при представлении всему комитету для голосования за статус WP, что эта проблема была решена без достаточного обдумывания последствий для расходящихся реализаций библиотеки, поскольку пользователи могут использовать SFINAE для наблюдения за поведением, отличным от идентичного кода. Проблема вернулась к статусу проверки и снова будет обсуждаться в Портленде с большой группой. Примечание для Портленда: Джон Спайсер согласился представлять интересы Core во время любого такого обсуждения в LWG.

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