Ответ 1
Короткий ответ
Нет.
объяснение
[namespace.std] говорит:
Обозначим через
F
стандартную библиотечную функцию ([global.functions]), статическую функцию-член стандартной библиотеки или создание шаблона стандартной библиотечной функции. ЕслиF
не обозначена адресуемой функцией, поведение программы C++ не определено (возможно, плохо сформировано), если она явно или неявно пытается сформировать указатель наF
[Примечание: возможные способы формирования таких указателей включают применение унарного оператора&
([expr.unary.op]),addressof
([addressof
]) или стандартное преобразование функции в указатель ([conv.func]). - примечание конца] Более того, поведение программы C++ не определено (возможно, плохо сформировано), если она пытается сформировать ссылку наF
или если она пытается сформировать указатель на член, обозначающий либо стандартную библиотеку, не статическая функция-член ([member.functions]) или создание шаблона функции-члена стандартной библиотеки.
Имея это в виду, давайте проверим два вызова std::invoke
.
Первый звонок
std::invoke(std::boolalpha, std::cout);
Здесь мы пытаемся сформировать указатель на std::boolalpha
. К счастью, [fmtflags.manip] спасает день:
Каждая функция, указанная в этом подпункте, является назначенной адресуемой функцией ([namespace.std]).
И boolalpha
- это функция, указанная в этом подпункте. Таким образом, эта линия правильно сформирована и эквивалентна:
std::cout.setf(std::ios_base::boolalpha);
Но почему это? Ну, это необходимо для следующего кода:
std::cout << std::boolalpha;
Второй звонок
std::cout << std::invoke(static_cast<ctype_func>(std::tolower), 'A') << "\n";
К сожалению, [cctype.syn] говорит:
Содержимое и значение заголовка
<cctype>
совпадают с заголовком стандартной библиотеки C<ctype.h>
.
Нигде tolower
явно обозначена адресуемая функция.
Поэтому поведение этой программы C++ не определено (возможно, плохо сформировано), поскольку она пытается сформировать указатель на tolower
, который не обозначен как адресуемая функция.
Заключение
Ожидаемый результат не гарантируется. На самом деле, код даже не гарантированно компилируется.
Это также относится к функциям-членам. [namespace.std] прямо не упоминает об этом, но из [member.functions] видно, что поведение программы C++ не определено (возможно, неправильно сформировано), если она пытается получить адрес объявленной функции-члена в стандартной библиотеке C++. По [member.functions]/2:
Для не виртуальной функции-члена, описанной в стандартной библиотеке C++, реализация может объявить другой набор сигнатур функций-членов при условии, что любой вызов функции-члена, который выберет перегрузку из набора объявлений, описанных в этом документе ведет себя так, как будто эта перегрузка была выбрана. [Примечание: Например, реализация может добавлять параметры со значениями по умолчанию или заменять функцию-член аргументами по умолчанию с двумя или более функциями-членами с эквивалентным поведением, или добавлять дополнительные подписи для имени функции-члена. - конец примечания]
Адрес перегруженной функции может быть взят только в контексте, который однозначно определяет, на какую версию перегруженной функции ссылаются (см. [Over.over]). [Примечание: поскольку контекст может определять, является ли операнд статической или нестатической функцией-членом, контекст также может влиять на то, имеет ли выражение тип "указатель на функцию" или "указатель на функцию-член". - конец примечания]
Следовательно, поведение программы не определено (возможно, плохо сформировано), если она явно или неявно пытается сформировать указатель на функцию-член в библиотеке C++.
(Спасибо за комментарий за указание на это!)