c++ 11/templates:选择正确的函数重载

C++11/templates: Select the correct overloading of a function

本文关键字:函数 重载 选择 templates c++      更新时间:2023-10-16

关于这个问题,这可能是过于简单化了,我在这里给出一个更复杂的例子。我假定的问题用以下代码描述:

// test3.cpp
using namespace std;
template<typename T>
struct exer
{
    template<typename R, typename... rArgs, typename... pArgs>
    R operator()(R(T::*f)(rArgs...), pArgs&&... args)
    {
       return (t.*f)(forward<pArgs>(args)...);
    }
    T t;
};
struct A
{
    int addition() { return 0; }
    template<typename... Args>
    int addition(int a, Args... args) { return a + addition(args...); }
};
struct B
{
public:
    template<typename... Args>
    int addition(Args&&... args)
    {
       return m_e(&A::addition, forward<Args>(args)...);
    }
private:
    exer<A> m_e;
};
int main()
{
    B b;
    cout << b.addition(1, 2, 3, 4) << endl;
}

这里的问题是,在B::addition的实例化中,&A::addition的类型是未知的,因为存在不同的过载。此外,B::addition也不知道必须使用哪个过载。直到函数被调用,它才知道编译器。但是,为了正确指定在exer<A>::operator()中必须使用哪个过载,我需要对&A::addition进行强制转换,以将其强制转换为正确的过载。

如何提取目标函数的正确重载类型?

更改问题。如果您可以使exer接受一个可调用对象,而不是一个指向成员函数的指针,如下所示:

template<typename T>
struct exer
{
    T t;
    template<typename F, typename... pArgs>
    auto operator()(F f, pArgs&&... args)
    -> decltype(f(t, forward<pArgs>(args)...))
    {
       return f(t, forward<pArgs>(args)...);
    }
};

那么你可以这样做:

struct B
{
public:
    template<typename... Args>
    int addition(Args&&... args)
    {
        struct Invoker {
            auto operator()(A& a, Args&&... args) const
                ->decltype(a.addition(std::forward<Args>(args)...))
            { return a.addition(std::forward<Args>(args)...); }
        };
        return m_e(Invoker(), forward<Args>(args)...);
    }
private:
    exer<A> m_e;
};

现在选择正确的A::addition是由编译器使用正常的重载解析规则完成的。

可以使用lambda表达式代替Invoker,这样可以减少一些重复:

        return m_e( [](A& a, Args&&... as) {
                      return a.addition(forward<Args>(as)...);
                    },
                    forward<Args>(args)...);