clang error when adding typecast in method of a template parameter

I have a template struct that takes as parameters the type of a method and the pointer to a method and wraps it in a C-like function:

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)...);
    }
};

The proxy struct works in simple scenarios as expected, eg:

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

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

The problem is when I use proxy inside macros that may unroll into:

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

in clang and the error is:

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);
                                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~

On the other hand GCC 4.8 is not reporting any error and everything works as expected.

My questions are:

  1. is there a way to workaround clang's error and
  2. is this a bug in clang that I should probably report?

Upvotes: 4

Views: 343

Answers (1)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275395

Your macro generates standards non-compliant code. In particular, a cast is not allowed in a in a non-type method pointer template argument. It is also redundant in this case.

So the easiest way to fix this is to change the macro:

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

And at point of use:

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

becomes:

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

and now it is correct according to the standard. Note "bob" and empty_flags are just placeholders for whatever really goes there. The name replacement may or may not be required.

Upvotes: 1

Related Questions