Constexpr на значение указателя на функцию-член - неопределенное поведение? - PullRequest
0 голосов
/ 07 января 2019

У меня проблема с простым механизмом отражения в C ++. Я хотел бы иметь один тип шаблона, который должен вести себя по-разному с разными указателями на функции-члены в качестве аргументов шаблона:

[Решение № 1, по стандарту это плохо]

Если у меня есть шаблон класса с типом класса и указателем на его функцию-член, я не могу частично специализироваться на нулевом указателе члена, потому что не могу специализировать «аргумент шаблона нетипичного типа с зависимым типом» (см .: https://en.cppreference.com/w/cpp/language/partial_specialization список аргументов [5])

template<class O, void(O::*foo)() = nullptr>
struct p
{};

template<class O, void(O::*foo)()>
struct p<O, nullptr>
{};

[Решение № 2, проблема GCC]

Если я попытаюсь специализироваться на выведенном значении constexpr, которое отражает указатель на член, у меня возникнут различные проблемы с компиляторами. GCC8.2 x64 говорит мне, что выражение nullptr == foo не является константой в контексте: p<A, &A::f> j;. Однако ARM GCC8 говорит, что все в порядке. Я думаю, что это некоторая проблема с разметкой памяти, что struct A не завершено в то время, когда механизм шаблонов пытается оценить конкретный указатель на функцию.

template<class O, void(O::*foo)() = nullptr, bool = nullptr == foo>
struct p
{};

template<class O, void(O::*foo)()>
struct p<O, foo, true>
{};

struct A
{
    void f();
    p<A, &A::f> j;
};

[Использование решения № 2, проблема MSVC]

Странно, что MSVC 19.5 x86 в порядке с вышеупомянутым, у него есть другая проблема. Это работает, в то время как структура A является автономной, или она наследует от одной структуры. Но когда есть две базовые структуры (X, Y), он умирает с внутренней ошибкой компилятора.

template<class O, void(O::*foo)() = nullptr, bool = nullptr == foo>
struct p
{};

template<class O, void(O::*foo)()>
struct p<O, foo, true>
{};

struct X{};
struct Y{};

struct A : X, Y
{
    void f();
    p<A> i;
    p<A, &A::f> j;
};

Clang7 хорошо работает со всем вышеперечисленным.

Может кто-нибудь объяснить, является ли это неопределенным поведением, или в стандарте есть какое-либо руководство по этой теме?

1 Ответ

0 голосов
/ 08 января 2019

Это CWG 2127 . По существу, у нас есть это ограничение в [temp.class.spec] :

Тип параметра шаблона, соответствующего специализированному нетипичному аргументу, не должен зависеть от параметра специализации.

Что в основном означает, что мы не можем напрямую заниматься тем видом специализации nullptr, который вы хотите выполнить. Который ... хромой. Но любую проблему в программировании можно решить, добавив еще один слой косвенности, верно?

template<class O, void(O::*foo)(), bool is_null>
struct p_impl { /* non-null case */ };

template<class O, void(O::*foo)()>
struct p_impl<O, foo, true> { /* null case */ };

template<class O, void(O::*foo)() = nullptr>
using p = p_impl<O, foo, foo == nullptr>;

С другой стороны, gcc, похоже, испытывает проблему при сравнении указателя на член неполного типа. Он отклоняет это:

template <bool> struct Z { };

struct C
{
    void f();
    Z<&C::f == nullptr> z; // not a constant expression
};

Это ошибка gcc 56428 , я думаю.

...