2016-03-14 1 views
3

Рассмотрим следующий код:Является ли стандарт C++ явно запрещать аргументы по умолчанию при вызовах с помощью указателей функций constexpr?

struct foo { 
    int bar(int, int = 0) { 
     return 0; 
    } 
}; 

constexpr auto ptr = &foo::bar; 

int main() { 
    return (foo{}.*ptr)(0); 
} 

Как и следовало ожидать, этот код не компилировать с последними версиями GCC, Clang и MSVC.

Допустимо, что гипотетический компилятор может передавать аргументы по умолчанию с помощью указателя функции-члена constexpr. Если этот компилятор успешно компилируется код, приведенный выше < редактировать > без предупреждений </редактировать >, эффективно передавая 0, 0 к foo::bar, что она по-прежнему соответствует стандарту ISO C++?

Допустимый ответ будет ссылаться на стандарт (или его рабочий проект). Я еще не нашел ответа в рабочем проекте N4567.

Редактировать: Если в стандарте нет комментариев по этой проблеме, я также соглашусь с этим в качестве ответа.

+0

Этот вопрос является дистилляцией моего предыдущего [связанного вопроса] (http://stackoverflow.com/questions/35966588) (плохой, в ретроспективе). –

+0

В «все равно будет соответствовать», вы имеете в виду: будет ли компилятор соответствовать? –

+0

Я не вижу там, где говорится, что аргументы по умолчанию не должны применяться даже для случая, отличного от constexpr –

ответ

6

Стандарт C++ явно не запрещает большинство плохо сформированных конструкций, включая этот. Этого достаточно, чтобы не было явно или неявно разрешено быть плохо сформированным.

Соответствующая реализация на С ++ позволяет принимать что-либо вообще, включая плохо сформированные программы на С ++. Однако требуется, по крайней мере, одна диагностика, если вход не является хорошо сформированной программой на С ++ (за исключением случаев, когда в стандарте присутствует явное предложение «нет необходимости диагностики»). Таким образом, вопрос о том, какой подходящий компилятор разрешен делать, зависит от вопроса о том, является ли рассматриваемая программа хорошо сформированной.

Для решения этого последнего вопроса мы должны установить, имеет ли значение constexpr. Ответ на это - это «нет». Ключевое слово constexpr вызывает определенные выражения, которые в противном случае не являются константными выражениями, чтобы стать таковыми и не имеют другого смысла. В свою очередь, константные выражения отличаются от простых выражений ванили в строго ограниченном числе четко определенных контекстов, таких как объявления массивов или экземпляры шаблонов. В таких контекстах непостоянное выражение сделает программу плохо сформированной. Поскольку такой контекст не присутствует в рассматриваемой программе, мы должны заключить, что constexpr не имеет никакого отношения к правильности программы.

В частности, постоянное выражение не освобождает выражение от его обязательства быть правильным по типу. В качестве простейшего примера,

`(int*)nullptr - (int*)nullptr` 

хорошо сформированы, в то время как

`(int*)nullptr - (double*)nullptr` 

является типом-неверны и, таким образом, плохо сформированы, несмотря на оба операнда быть постоянные выражения, известные во время компиляции, чтобы быть равным до nullptr.

Отказ от ответственности: C-стиль применяется только для демонстрационных целей, поскольку они лучше читаются в коротких фрагментах кода. Не используйте их в производственном коде.

Итак, мы должны проверить, хорошо ли сформирована программа constexpr или нет.Этот вопрос, на удивление, не имеет прямого ответа в стандарте и вообще не может дать никакого ответа. Согласно статически типизированной природе C++, вызов должен быть плохо сформирован, но я не мог найти прямого утверждения об этом. Вместо того, чтобы размышлять о потенциальных последствиях этого, я бы предпочел объявить это техническим дефектом стандарта и назвать его днем.

Стандарт делает косвенно утверждать, что аргументы функции по умолчанию являются свойством функции декларации, а не сами функций:

(8.3.6/4) Объявлений в разных областях имеют совершенно разные наборы аргументов по умолчанию

Таким образом, указатель функции, являющийся сущностью, которая ссылается на функцию, а не на объявление функции, не должен иметь примененных аргументов по умолчанию.

+0

Отличный ответ. В более раннем комментарии я сказал: «Я не уверен, что ответственность за соблюдение находится в программе или компиляторе. Практически я считаю, что разница не имеет смысла». Теперь я вижу, что разница довольно значительна! Я запомню это в будущем - спасибо. –

Смежные вопросы