Question

I don't understand why clang reject this code. I got it from my friend and it compiled on VisualStudio for him... I have TOT of clang.

#include <utility>
#include <iostream>

template< typename Signature >
class Delegate;

template< typename Ret, typename Param >
class Delegate< Ret(Param) >
{
public:

   Ret operator()(Param&& p_param)
   {
      return m_ifunc(m_obj, std::forward< Param >(p_param));
   }

   template< typename ObjType, typename Ret(ObjType::*Method)(Param) >
   friend auto createDelegate(ObjType * const p_obj)
   {
      Delegate< Ret(Param) > del;
      del.m_obj = p_obj;
      del.m_ifunc = &ifunction< ObjType, Method >;
      return del;
   }

private:

   void * const m_obj = nullptr;
   Ret (*m_ifunc)(void*, Param&&) = nullptr;

   template< typename ObjType, typename Ret(ObjType::*Method)(Param) >
   static Ret ifunction(void * const p_obj, Param&& p_param)
   {
      ObjType * const obj = (ObjType * const) p_obj;
      return (obj->*Method)(std::forward< Param >(p_param));
   }
};

struct Test
{
   void test(int x)
   {
      std::cout << x << std::endl;
   }

};

int main()
{
   Test t;

   Delegate< void(int) > d = Delegate< void(int) >::createDelegate< Test, &Test::test >(&t);

   d(5);
}

This is the errors that I get Anybody understand what is going on? I have seen this way of specifying the template argument for function pointers I guess there is missing something do to the strictnees of clang.

main.cpp:17:41: error: expected a qualified name after 'typename'
   template< typename ObjType, typename Ret(ObjType::*Method)(Param) >
                                        ^
main.cpp:31:41: error: expected a qualified name after 'typename'
   template< typename ObjType, typename Ret(ObjType::*Method)(Param) >
                                        ^
main.cpp:52:53: error: no member named 'createDelegate' in 'Delegate<void (int)>'
   Delegate< void(int) > d = Delegate< void(int) >::createDelegate< Test, &Test::test >(&t);
                             ~~~~~~~~~~~~~~~~~~~~~~~^
main.cpp:52:69: error: 'Test' does not refer to a value
   Delegate< void(int) > d = Delegate< void(int) >::createDelegate< Test, &Test::test >(&t);
                                                                    ^
main.cpp:39:8: note: declared here
struct Test
       ^
main.cpp:52:82: error: definition or redeclaration of 'test' not allowed inside a function
   Delegate< void(int) > d = Delegate< void(int) >::createDelegate< Test, &Test::test >(&t);
                                                                           ~~~~~~^
main.cpp:52:86: error: expected ';' at end of declaration
   Delegate< void(int) > d = Delegate< void(int) >::createDelegate< Test, &Test::test >(&t);
                                                                                     ^
Was it helpful?

Solution

There are several problems with your code, and I'm pretty certain it never compiled on VisualStudio in its current form. In any case, I can't get it to compile on VS2013. Here are the errors:

template< typename ObjType, typename Ret(ObjType::*Method)(Param) >
//                          ^^^^^^^^
// the member function pointer is a non-type template parameter, remove typename
friend auto createDelegate(ObjType * const p_obj)
// ^^^^
// you've declared this as a friend, but call it within main() as if it is a
// static member function, change 'friend' to 'static'


template< typename ObjType, typename Ret(ObjType::*Method)(Param) >
//                          ^^^^^^^^
// same as above, remove typename
static Ret ifunction(void * const p_obj, Param&& p_param)

The m_obj data member is a const pointer, yet you try to point it to a new object within createDelegate

void * const m_obj = nullptr;
//     ^^^^^
// remove the const

After making these changes

template< typename Signature >
class Delegate;

template< typename Ret, typename Param >
class Delegate< Ret(Param) >
{
public:

   Ret operator()(Param&& p_param)
   {
      return m_ifunc(m_obj, std::forward< Param >(p_param));
   }

   template< typename ObjType, Ret(ObjType::*Method)(Param) >
   static auto createDelegate(ObjType * const p_obj)
   {
      Delegate< Ret(Param) > del;
      del.m_obj = p_obj;
      del.m_ifunc = &ifunction< ObjType, Method >;
      return del;
   }

private:

   void * m_obj = nullptr;
   Ret (*m_ifunc)(void*, Param&&) = nullptr;

   template< typename ObjType, Ret(ObjType::*Method)(Param) >
   static Ret ifunction(void * const p_obj, Param&& p_param)
   {
      ObjType * const obj = (ObjType * const) p_obj;
      return (obj->*Method)(std::forward< Param >(p_param));
   }
};

Now the code compiles, and outputs 5. Live demo


An additional change is needed for this to compile on VS2013 (release version, don't know about the CTP). Since VS2013 doesn't implement C++14's return type deduction for ordinary functions, createDelegate needs to have the return type specified explicitly

template< typename ObjType, Ret(ObjType::*Method)(Param) >
static Delegate< Ret(Param) > createDelegate(ObjType * const p_obj)
{ /* ... */ }

Finally, just to make sure you're aware of the alternatives:

Test t;
auto d = std::bind(&Test::test, t, std::placeholders::_1);
d(5);    // prints 5
std::function<void(int)> d2 = std::bind(&Test::test, t, std::placeholders::_1);
d2(5);   // prints 5
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top