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

Может ли "const T *" соответствовать указателю на свободную функцию?

В связанном вопросе он сказал, что нет такой вещи, как указатель на не-членную функцию const. Кроме того, в С++ 11 8.3.5/6 говорится

Эффект cv-qualifier-seq в объявлении функции не совпадает с добавлением cv-qualification поверх типа функции. В последнем случае cv-квалификаторы игнорируются. [Примечание: тип функции, имеющий cv-qualifier-seq, не является cv-квалифицированным типом; нет типов функций с квалификацией cv. -end note]

Если я правильно понимаю, это означает, что нет такой вещи, как функция, не являющаяся членом-константой. (Хотя такие функции не являются константами, они не могут быть изменены согласно 3.10/6). В частности, указатели на функцию const не имеют смысла.

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

#include <iostream>

void f() {}

template <typename T> void g(      T*) { std::cout << "non const" << std::endl; }
template <typename T> void g(const T*) { std::cout << "const    " << std::endl; }

int main() {
     g(f);
}

При компиляции с GCC и Intel код выводит "non const", как я ожидал бы из приведенной выше цитаты. Тем не менее, вывод "const" при компиляции с Clang и Visual Studio.

Правильно ли моя интерпретация?

Update:

Следуя комментариям, я пытаюсь уточнить, что я не говорит о функциях const member. Меня интересуют функции, отличные от членов (но те же аргументы, вероятно, применимы и к нестационарным функциям-членам). Я также изменил название вопроса, чтобы уточнить его.

В соответствии с упомянутым выше разрешением g(f) приведенная ниже строка является ilegal для GCC и Intel, но не для Clang и Visual Studio

const auto* ptr = &f;

Обновление 2:

Я согласен с интерпретацией Энди Проула и выбрал его ответ. Однако после этого мне стало известно, что этот вопрос является CWG открытой проблемой.

4b9b3361

Ответ 1

Если я правильно понимаю, это означает, что нет такой вещи, как функция, не являющаяся членом-константой. (Хотя такие функции не являются константами, они не могут быть изменены согласно 3.10/6). В частности, указатели на функцию const не имеют смысла.

Да, нет функции типа const, и попытки создать ее игнорируются из-за того же самого параграфа, который вы указали. Это важно, потому что программа, которая каким-либо образом создает тип функции const, не плохо сформирована (как это было в С++ 03); просто его попытка игнорируется, и вместо него рассматривается тип функции не const.

Вероятно, что GCC и ICC не применяются, потому что, когда перегрузка не const удалена, программа не компилирует:

#include <iostream>

void f() {}

template <typename T> void g( T const*) 
{ 
   std::cout << "const    " << std::endl; 
}

int main() {
     g(f); // ERROR with GCC and ICC, compiles with Clang
}

Относительно вашей интерпретации:

При компиляции с GCC и Intel код выводит "non const", как я ожидал бы из приведенной выше цитаты. Однако при компиляции с Clang и Visual Studio вывод "const". Является ли моя интерпретация правильной?

Я так не верю. Насколько я могу судить, Кланг прав.

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

В соответствии с параграфом 8.3.5/7 стандарта С++ 11:

[...] Эффект cv-qualifier-seq в объявлении функции не совпадает с добавлением cv-qualification сверху типа функции. В последнем случае cv-квалификаторы игнорируются. [...]

Это эффективно делает второй шаблон функции жизнеспособным для разрешения вызова (первый, очевидно, есть). Но поскольку оба функциональных шаблона жизнеспособны, вступает в игру пункт 13.3.3.1 о разрешении перегрузки:

Учитывая эти определения, жизнеспособная функция F1 определена как лучшая функция, чем другая жизнеспособная функция F2, если для всех аргументов я ICSi (F1) не является худшей последовательностью преобразования, чем ICSi (F2), а затем

- для некоторого аргумента j ICSj (F1) является лучшей последовательностью преобразования, чем ICSj (F2), или, если не это,

- контекст представляет собой инициализацию путем пользовательского преобразования (см. 8.5, 13.3.1.5 и 13.3.1.6) и стандартная последовательность преобразования из возвращаемого типа F1 в тип назначения (т.е. тип инициализация объекта) является лучшей последовательностью преобразования, чем стандартная последовательность преобразования из тип возврата F2 к типу назначения. [...] или, если не это,

- F1 - это не шаблонная функция, а F2 - специализированная функция шаблона или, если не это,

- F1 и F2 являются специализированными шаблонами функций, а шаблон функции для F1 более специализирован, чем шаблон для F2 в соответствии с правилами частичного упорядочения, описанными в 14.5.6.2.

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