Если вы прочитаете на странице cppreference, вы заметите это предложение
В противном случае (если T является cv- или ref-квалифицированным типом функции), предоставляется тип typedef члена, который равен Тип T.
Функция имеет свои типы. Обычно в нормальном коде вы видите типы типа int(int)
, то есть тип функции, которая принимает одно целое число и возвращает целое число. Это тип аргумента, который std::function
ожидает, например, std::function<int(int)>
.
Однако набор типов функций также содержит странности, которые относятся к функциям-членам. Например,
struct foo {
int bar(int) const;
};
int(int) const
является типом функции bar
. Хотя этот тип существует в системе типов, его использование ограничено.
[dcl.fct]
6 A cv-qualifier-seq или ref-qualifier должен входить только в:
- тип функции для нештатной c функции-члена,
- тип функции, для которой указатель на член ссылается,
- на тип функции верхнего уровня объявления функции typedef или объявления псевдонима,
- идентификатор типа в аргументе по умолчанию для параметра типа ([temp .param]), или
- идентификатор типа аргумента шаблона для параметра типа ([temp.names]).
Эффект квалификатора cv -seq в деклараторе функции - это не то же самое, что добавить cv-квалификацию поверх типа функции. В последнем случае cv-квалификаторы игнорируются. [Примечание: тип функции, имеющий cv-qualifier-seq, не является cv-квалифицированным типом; не существует cv-квалифицированных типов функций. - конец примечания] [Пример:
typedef void F();
struct S {
const F f; // OK: equivalent to: void f();
};
- конец примера] Тип возвращаемого значения, список параметров-типов, квалификатор ref и cv-qualifier-seq, но не аргументы по умолчанию ( [dcl.fct.default]) или спецификация исключения ([exc.spec]), являются частью типа функции.
Таким образом, эта черта позволяет вам передавать ей тип функции, такой как int() const
и ожидается, что он вернет его без изменений.
Вот тут и приходит try_add_pointer
. Поскольку, как видно из приведенного выше списка, нет регулярных указателей на функции такого рода, мы получим замену ошибка в typename std::remove_reference<T>::type*
. Но благодаря SFINAE существует запасной вариант.