Упрощенный пример из недавнего сообщения в блоге:
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::*)() для меня...