【问题标题】:Passing member function pointer as a template type将成员函数指针作为模板类型传递
【发布时间】:2014-05-14 00:45:10
【问题描述】:

我不明白为什么 clang 拒绝此代码。我从我的朋友那里得到它,并在 VisualStudio 上为他编译了它......我有很多铿锵声。

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

【问题讨论】:

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


    【解决方案1】:

    您的代码存在几个问题,我很确定它从未以当前形式在 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
    

    【讨论】:

    • 是的,你是对的。我犯了一个错误,原始代码没有将该函数作为静态函数调用,并且clang仍在抱怨。 see this
    • @monamimani 我认为我之前的解释是错误的。您在 gcc-4.8、4.9 和 VS2013 上的评论 works as is 中链接到的代码。所以你可能发现了一个 clang 错误。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-26
    • 1970-01-01
    • 2018-12-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多