4

基类是:

#include <memory>

namespace cb{

template< typename R, typename ... Args >
class CallbackBase
{
public:
    typedef std::shared_ptr< CallbackBase< R, Args... > >
            CallbackPtr;

    virtual ~CallbackBase()
    {
    }
    virtual R Call(  Args ... args) = 0;
};
} // namespace cb

派生类是这样的:

namespace cb{
template< typename R, typename ... Args >
class FunctionCallback : public CallbackBase< R, Args... >
{
public:
    typedef R (*funccb)(Args...);

    FunctionCallback( funccb cb_ ) : 
        CallbackBase< R, Args... >(),
        cb( cb_ )
    {
    }
    virtual ~FunctionCallback()
    {
    }
    virtual R Call(Args... args)
    {
      return cb( args... );
    }
private:
  funccb cb;
};
} // namespace cb

创建函数:

namespace cb{
template < typename R, typename ...Args >
typename CallbackBase< R, Args... >::CallbackBasePtr
    MakeCallback( typename FunctionCallback< R, Args... >::funccb cb )
{
    typename CallbackBase< R, Args... >::CallbackBasePtr
        p( new FunctionCallback< R, Args... >( cb )
);
    return p;
}
} // namespace cb

和例子:

bool Foo_1args( const int & t)
{
    return true;
}
int main()
{
    auto cbObj = cb::MakeCallback( & Foo_1args );
}

我不断收到此错误:

error: no matching function for call to ‘MakeCallback(bool (*)(const int&))’
error: unable to deduce ‘auto’ from ‘&lt;expression error>’

我试图改变它,但我不知道如何解决。

那么,有什么问题呢?以及如何解决这个例子?

4

4 回答 4

7

通过一个更简单的例子,这个问题可能是有意义的。尝试在此处识别问题:

template <typename T>
struct id { typedef T type; };

template <typename T>
void foo(typename id<T>::type x);

foo(5); // error

问题是编译器无法推断出T应该是什么;它没有在任何地方直接使用。你必须明确地提供它:foo<int>(5),或者让它以其他方式推断它:

template <typename T>
void foo(typename id<T>::type x, T y);

foo(5, 7); // okay, T is int because 7 is int

这是有道理的:编译器如何确定T提供给 的 'id导致id<T>::type匹配?可能会有专业化,如果可能的话,整个事情无论如何都会很昂贵。


同样,编译器也无法推断RArgs. 相反,您应该这样做:

template < typename R, typename ...Args >
typename CallbackBase< R, Args... >::CallbackBasePtr
    MakeCallback( R cb(Args...) )
{
    typename CallbackBase< R, Args... >::CallbackBasePtr
        p( new FunctionCallback< R, Args... >( cb ));

    return p;
}

最后,您还有其他需要修复的小问题,Xeo 已经概述了这些问题。

于 2011-04-13T23:12:58.940 回答
4

修复了一些 type-o 和专门的 MakeCallback 以接受函数指针。正如 GMan 所说,您对 MakeCallback 的模板参数处于不可演绎的上下文中。

#include <memory>

template< typename R, typename ... Args >
class CallbackBase
{
public:
    typedef std::shared_ptr< CallbackBase< R, Args... > >
            CallbackPtr;

    virtual ~CallbackBase()
    {
    }
    virtual R Call(  Args ... args) = 0;
};

template< typename R, typename ... Args >
class FunctionCallback : public CallbackBase< R, Args... >
{
public:
    typedef R (*funccb)(Args...);

    FunctionCallback( funccb  cb_ ) : 
        CallbackBase< R, Args... >(),
        cb( cb_ )
    {
    }
    virtual ~FunctionCallback()
    {
    }
    virtual R Call(Args... args)
    {
      return cb( args... );
    }
private:
  funccb cb;
};

template < typename R, typename ...Args >
typename CallbackBase< R, Args... >::CallbackPtr
    MakeCallback( R (*cb)(Args...)  )
{
    typename CallbackBase< R, Args... >::CallbackPtr
        p( new FunctionCallback< R, Args... >( cb )
);
    return p;
}

bool Foo_1args( const int & t)
{
    return true;
}
int main()
{
    auto cbObj = MakeCallback( & Foo_1args );
}

更新:

C++ 标准在 14.8.2.5 [temp.deduct.type] 第 5 - 6 段中定义了非推导上下文。那里有一个项目符号列表,我不会声称完全理解。我的标记是:

每当您在模板参数之后看到“::”时,该模板参数都处于非推导上下文中,这意味着它必须在调用站点明确指定。

于 2011-04-13T23:17:53.000 回答
4

回忆我在其他答案的评论中提到的内容:

  • 首先,正如@GMan 所说,您的论点MakeCallback是不可演绎的。
  • 其次,您的返回类型MakeCallback错误。应该是CallbackPtr,因为CallbackBasePtrtypedef 不存在。这导致SFINAE开始介入,并且即使在参数固定时也不将您的函数视为可能调用的函数。
  • 第三,你的FunctionCallback构造函数想要一个funccb* 指针,而funccb已经是一个(函数)指针,所以你必须传递一个指向函数指针的指针,例如。new FunctionCallback(&cb)
于 2011-04-13T23:31:22.353 回答
4

使用<functional>比重新发明更好……直接从编译器的实现中复制也更好。

一般来说,使用更少的模板参数也是一件好事。

但是,解决这些问题总是很诱人……所以,知道我在做什么,但现在不直接看,这就是我的处理方式。

简单Call的仿函数的代码不会专门用于不同类型的仿函数,所以它应该在一般模板案例中。

要对通用模板进行细微调整,最好使用特征类。

template< typename F, typename = void >
struct callback_traits {
    typedef F const &local_type; // fallback case: only keep a reference
};

template< typename F >
struct callback_traits< F,
    typename std::enable_if< // GCC 4.4 missing is_copy_constructible:
        std::is_constructible< F, F const& >::value
    >::type > {
    typedef F local_type; // better to keep a copy as this is a callback
};

template< typename F >
struct Callback {
    typedef typename callback_traits< F >::local_type local_type;
    local_type fn;

    Callback( local_type const &fn_in ) : fn( fn_in ) {}
    template< typename ... Args >
    typename std::result_of< local_type( Args ... ) >::type
    Call( Args ... a )
        { return fn( a ... ); }
};
于 2011-04-13T23:35:21.003 回答