Подтвердить что ты не робот

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

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

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

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

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

4b9b3361

Ответ 1

Существует простой трюк:

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), вызывает вызов второй перегрузки (или, если, скажем, кто-то передал ей аргументы).

Ответ 2

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

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

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