c++ - 将成员函数指针作为模板类型传递

标签 c++ c++11 clang c++14

我不明白为什么 clang 会拒绝这段代码。我从我的 friend 那里得到它并在 VisualStudio 上为他编译...我有 clang 的 TOT。

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

这是我得到的错误 有人知道发生了什么事吗?我已经看到这种为函数指针指定模板参数的方法,我猜想缺少一些对 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);
                                                                                     ^

最佳答案

您的代码有几个问题,我很确定它从未以当前形式在 VisualStudio 上编译过。无论如何,我无法在 VS2013 上编译它。以下是错误:

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)

m_obj 数据成员是一个 const 指针,但您试图将它指向 createDelegate 中的一个新对象

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

做出这些改变之后

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

现在代码编译并输出5Live demo


要在 VS2013(发行版,不知道 CTP)上编译,需要进行额外更改。由于VS2013没有实现C++14对普通函数的返回类型推导,createDelegate需要显式指定返回类型

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

最后,只是为了确保您了解替代方案:

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

关于c++ - 将成员函数指针作为模板类型传递,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23643878/

相关文章:

c++ - 内联命名空间和 using 指令在 C++11 中的区别?

c++ - C++中初始化数组容器的方法

C++17 编译器不应该发现对未定义值的引用传递吗?

c++ - 使用内联 ASM 进行非常规调用

c++ - memset如何通过-1初始化一个整数数组?

c++ - 你能继承同一个类两次吗?

c++ - 在 lambda 中没有按值分配拷贝

c++ - 如果键已经存在,则在不删除指针的情况下将 unique_ptr 插入映射的有效方法

c++ - Aarch64 上 C++11 原子的部分重新排序

c++ - 如何设置 CMake 与 clang 交叉编译 Windows 上嵌入的 ARM?