Упрощенный пример из недавнего сообщения в блоге:
struct B { void f(); };
struct D : B { };
constexpr auto as_d = static_cast<void(D::*)()>(&D::f); // (1)
template <void (D::*)()>
struct X { };
X<as_d> x; // (2)
gcc, clang и MSVC все принимают объявление as_d
помеченного (1)
. gcc и clang оба отклоняют объявление x
помечено (2)
, но MSVC принимает его.
Оба сообщения gcc и clang указывают, что они знают, что as_d
является указателем на элемент B
лязг:
<source>:9:3
: ошибка: извините, аргумент шаблона типа не указателя типаvoid (D::*)()
который относится к членуB::f
другого класса, еще не поддерживается
НКА:
<source>:9:7
: error:void (D::*)(){((void (D::*)())B::f), 0}
не является допустимым аргументом шаблона для типаvoid (D::*)()
Кто прав? Если gcc/clang, каково правило, от которого мы справляемся? Кажется, что as_d
является преобразованным постоянным выражением типа void (D::*)()
для меня...