Является ли 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 6

2 ответа:

Простая причина заключается в том, что использование S::f ограничено для членов класса.

[expr.prim.id]

2 id-выражение, которое обозначает нестатический элемент данных или нестатическая функция-член класса может использоваться только:

  • как часть доступа к члену класса, в котором выражение объекта ссылается на класс члена или класс, производный от этого класса, или
  • для формирования указателя на элемент ([expr.унарный.op]), или
  • Если это id-выражение обозначает нестатический элемент данных и оно появляется в неявном операнде.

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

Я могу только догадываться, почему это не допускается, , хотя я ранее задавал этот вопрос.

Стоит отметить, что decltype(&S::f) работает здесь как указатель на тип функции-члена,
опять же, если только f не называет набор перегруженных функций (членов).

Сам тип функции может быть извлечен из типа указателя на функцию-член.
Если функция-член имеет квалификацию cv-или-ref, то она имеет отвратительный тип функции.
здесь отсутствуют черты std - библиотека, подобная Boost.CallableTraits помогает.