ошибка clang при добавлении typecast в метод параметра шаблона

У меня есть шаблонная структура, которая принимает в качестве параметров тип метода и указатель на метод и оборачивает его в C-подобную функцию:

template <typename T, T> struct proxy;

template <typename T, typename R, typename ...Args, R (T::* mf)(Args...)>
struct proxy<R (T::*)(Args...), mf>
{
    static R call(T& obj, Args&&... args)
    {
        return (obj.*mf)(std::forward<Args>(args)...);
    }
};

Структура proxy работает в простых сценариях, как и ожидалось, например:

struct Foo
{
    int foo(int x)
    {
        return x + 1;
    }
};

...
Foo f;
proxy<int(Foo::*)(int), &Foo::foo>::call(f, 10);

Проблема в том, что когда я использую proxy внутри макросов, которые могут разворачиваться в:

proxy<decltype((int(Foo::*)(int))(&Foo::foo)), (int(Foo::*)(int))(&Foo::foo)>::call(f, 10);

в clang и ошибка:

error: non-type template argument is not a pointer to member constant
proxy<decltype((int(Foo::*)(int))(&Foo::foo)), (int(Foo::*)(int))(&Foo::foo)>::call(f, 10);
                                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~

С другой стороны, GCC 4.8 не сообщает об ошибках, и все работает так, как ожидалось.

Мои вопросы:

  1. есть ли способ обойти ошибку clang и
  2. это ошибка в clang, о которой я, вероятно, должен сообщить?

person Pan. Christopoulos Charitos    schedule 11.04.2014    source источник
comment
Можем ли мы увидеть макрос случайно? Наверное, это неважно, но просто любопытно.   -  person Suedocode    schedule 12.04.2014
comment
Этот бросок не должен быть обязательным. Выбор перегрузки должен работать, поскольку вы уже указали тип с помощью предыдущих аргументов шаблона. Проблема, вероятно, заключается в том, что аргумент шаблона указателя, не являющийся типом, должен быть записан как & id-expression или просто id-expression для обычных (не являющихся членами) функций.   -  person dyp    schedule 12.04.2014
comment
decltype((int(Foo::*)(int))(&Foo::foo)) Какое-то странное выражение. Если у вас есть тип для преобразования, почему вы используете decltype и приведение типов? Или это из аргумента макроса?   -  person dyp    schedule 12.04.2014
comment
Опечатка: указатель на член как аргумент шаблона, не являющийся типом, должен быть выражен, как описано в 5.3.1, где говорится о формировании такого указателя через &class_name::member_name. Это, вероятно, приводит к тому же ограничению: приведение типов не разрешено.   -  person dyp    schedule 12.04.2014
comment
Макрос: #define ANKI_LUA_METHOD_FLAGS(name_, methodPtr_, flags_) \ ANKI_LUA_FUNCTION_AS_METHOD_FLAGS(name_, \ (&proxy‹decltype(methodPtr_), methodPtr_›::func), flags_)   -  person Pan. Christopoulos Charitos    schedule 12.04.2014
comment
Можно ли изменить макрос?   -  person Oktalist    schedule 12.04.2014
comment
Или снять гипс? (Или вы пытались использовать его для выбора конкретной перегрузки foo?)   -  person Oktalist    schedule 12.04.2014


Ответы (1)


Ваш макрос генерирует код, не соответствующий стандартам. В частности, приведение типов не разрешено в аргументе шаблона указателя метода, отличного от типа. В данном случае это тоже лишнее.

Поэтому самый простой способ исправить это — изменить макрос:

#define WORKING_LUA_METHOD_FLAGS(name_, methodType_, methodPtr_, flags_) \
  ANKI_LUA_FUNCTION_AS_METHOD_FLAGS(name_, \
  (&proxy<methodType_, methodPtr_>::func), flags_)

И в момент использования:

ANKI_LUA_METHOD_FLAGS( "bob", (int(Foo::*)(int))(&Foo::foo), empty_flags )

становится:

WORKING_LUA_METHOD_FLAGS( "bob", int(Foo:::*)(int), &Foo::foo, empty_flags )

и теперь это правильно по стандарту. Обратите внимание, что "bob" и empty_flags — это просто заполнители для всего, что там действительно есть. Замена имени может потребоваться, а может и не потребоваться.

person Yakk - Adam Nevraumont    schedule 12.04.2014
comment
@dyp вы бы поверили, что копипаста кодирует на телефоне? - person Yakk - Adam Nevraumont; 12.04.2014
comment
Может быть, вам нужен один с большим дисплеем? ;) - person dyp; 12.04.2014