可变模板匹配和SFINAE?

时间:2015-10-17 05:44:15

标签: c++ variadic

template<typename Signature>
class myfunction   //basic class template
{
};

template<typename R, typename... Args>
class myfunction<R (Args...)>   //normal function  specialized edition 
{
    typedef R (*Ptr)(Args...);
    Ptr m_p;
public:
myfunction(Ptr p) : m_p(p)
{

}
R operator()(Args... args)
{
    return m_p(args...);
}
};

template<typename R, typename T, typename ... Args>
class myfunction<R (T*, Args...)>  //member function specialized edition one
{
    typedef R (T::* mPtr)(Args...);
    mPtr m_p;
public:
    myfunction(mPtr p):  m_p(p)
    {

    }
    R operator()(T* likeThis, Args...args)
    {
        return   (likeThis->*m_p)(args...);
    }
};


template<typename R, typename T, typename ... Args>
class myfunction<R (T, Args...)>   //member function specialized edition two
{
    typedef R (T::* mPtr)(Args...);
    mPtr m_p;
public:
    myfunction(mPtr p):  m_p(p)
    {

    }
    R operator()(T likeThis, Args...args)
    {
        return   (likeThis.*m_p)(args...);
    }
};

template<typename R, typename T, typename ... Args>
class myfunction<R(T&, Args...)>   //member function specialized edition three
{
    typedef R (T::* mPtr)(Args...);
    mPtr m_p;
public:
    myfunction(mPtr p):  m_p(p)
    {

    }
    R operator()(T& likeThis, Args...args)
    {
    return   (likeThis.*m_p)(args...);
    }
};

int func1()
{
    cout << "func1";
    return 0;
    }

void func2(int x)
{
    cout << "func2";
    cout << x ;
}
int main()
{
    myfunction<int(void)> f1(func1);
    f1();
    myfunction<void(int)> f2(func2);//this will fail, why?
    f2(1);   
    return 0;
}

我想在标准库中修改函数包装器。 测试代码如上所述。 但是,f1可以算一个合适的,这是正常的功能专用版。虽然f2首先匹配成员函数专用版本两个,但是匹配失败后,应该去匹配正常功能专用版然后成功吗?这就是SFINAE的意思,对不对? 在我评论出会员功能专业版二之后,它会匹配一个,那为什么? 请帮帮我。

1 个答案:

答案 0 :(得分:0)

正如评论中指出的那样 - 这个专业化正在接管你的一个arg自由函数:

template<typename R, typename T, typename ... Args>
class myfunction<R (T, Args...)>   //member function specialized edition two
{
    typedef R (T::* mPtr)(Args...);
    mPtr m_p;
public:
    myfunction(mPtr p):  m_p(p)
    {

    }
    R operator()(T likeThis, Args...args)
    {
        return   (likeThis.*m_p)(args...);
    }
};

简单回答就是删除此专业化,您的程序开始编译。

但是 - std::function实现并不像你想象的那么容易。您需要使用type erasure技术来模仿其行为 - 我的意思是myFunction<R(Arg...>myFunction应该为所有 - 免费函数和成员函数服务 - 仅在构造特定对象实例时 - 您应该选择&#34;实施&#34;通过参数类型 - 如果它是成员函数或自由函数。

首先,您必须定义任何函数调用抽象:

template<typename R, typename T, typename ... Args>
class AnyFunctionCall
{
public:
    virtual ~AnyFunctionCall() {}

    virtual R call(T arg, Arg&&... args) const = 0;
};

我看到你已经知道如何为自由函数和成员函数实现这个接口。

template<typename R, typename T, typename ... Args>
class myfunction<R (T, Args...)>  
{
    std::unique_ptr<AnyFunctionCall> implementation;

public:
    template <typename Functor>
    myfunction(Functor p):  m_p(makeFunctionCall(std::forward<Functor>(p)))
    {

    }
    R operator()(T arg, Arg&&... args)
    {
        return implementation->call(arg, args...);
    }
};

你看 - 它需要有一个参数(自由函数的对象或第一个参数)。对于零参数函数,您可以对自由函数myfunction<R ()>进行简单的特化。