Является ли decltype нестатической функции-члена плохо сформированным?
Я не уверен, что полностью понимаю [dcl.type]/4.3
:
Для выражения
e
тип, обозначаемыйdecltype(e)
, определяется следующим образом:
- [...]
- (4.3) в противном случае, если
e
является непарентизированным id-выражением или непарентизированным доступом к члену класса,decltype(e)
является типом сущности, названнойe
. Если такой сущности нет или еслиe
называет набор перегруженных функций, то программа плохо сформирована ;- [...]
Для меня подчеркнутая часть относится как к id-выражению , так и к доступу к члену класса, верно?
Играя с моим любимым компилятором, я получаю следующее.✓ принимается компилятором
namespace N { void f() {} }
using type = decltype(N::f);
type* pf = N::f;
Хорошо, я думаю; N::f
является непарентизированным id-выражением и не называет набор перегруженных функций.
✗ отклонено компилятором
namespace N { void f() {} void f(int) {} }
using type = decltype(N::f); // error: decltype cannot resolve address of overloaded function
type* pf = N::f;
Ok; N::f
действительно называет набор перегруженных функции.
✗ отклонено компилятором
struct S { void f(){} };
using type = decltype(S::f); // error: invalid use of non-static member function 'void S::f()'
type* pf = &S::f;
Хм? S::f
назовет ли набор одной перегруженной функции?
В целом, является ли мое понимание [dcl.type]/4.3
просто плохим? это GCC багажник не так? как? ни одного? камулокс?
2 ответа:
Простая причина заключается в том, что использование
S::f
ограничено для членов класса.[expr.prim.id]
2 id-выражение, которое обозначает нестатический элемент данных или нестатическая функция-член класса может использоваться только:
- как часть доступа к члену класса, в котором выражение объекта ссылается на класс члена или класс, производный от этого класса, или
- для формирования указателя на элемент ([expr.унарный.op]), или
- Если это id-выражение обозначает нестатический элемент данных и оно появляется в неявном операнде.
Последний маркер, относящийся к вашему коду, применяется только к нестатическому элементу данных. Нет никакого положения о функциях.
Я могу только догадываться, почему это не допускается, , хотя я ранее задавал этот вопрос.
Стоит отметить, что
decltype(&S::f)
работает здесь как указатель на тип функции-члена,
опять же, если толькоf
не называет набор перегруженных функций (членов).Сам тип функции может быть извлечен из типа указателя на функцию-член.
Если функция-член имеет квалификацию cv-или-ref, то она имеет отвратительный тип функции.
здесь отсутствуют черты std - библиотека, подобная Boost.CallableTraits помогает.