检索对象的函数运算符的参数类型

时间:2016-09-21 12:02:59

标签: c++ templates function-pointers c++03

我有一个包装器,它将带有多个参数的函数转换为只带一个参数的函数(提供其他参数的值)。此代码适用于函数

template <class R, class F, class A0, class A1>
class CMyWrapper {
     F m_f;
     A0 m_default_a0;

public:
     CMyWrapper(F f, const A0 &default_a0)
         :m_f(f), m_default_a0(default_a0)
     {}

     R operator ()(const A1 &a1) const
     {
         return m_f(m_default_a0, a1);
     }
};

template <class R, class A0, class A1>
CMyWrapper<R, R (*)(const A0&, const A1&), A0, A1>
    SupplyConstArg(R (*fun)(const A0&, const A1&), const A0 &default_a0)
{
    return CMyWrapper<R, R (*)(const A0&, const A1&), A0, A1>(fun, default_a0);
}

double MyFunc(const double &x, const double &y); // some function

现在我可以这样做,例如调用SupplyConstArg(MyFunc, 1.23)(4.56)的{​​{1}}(此表达式的左侧部分是一个提供常量第一个参数的函数对象)。到目前为止一切都很好。

但是,我在编写用于函数对象而不是函数的类似函数时遇到了一些困难(我希望在可能的情况下出于性能原因避免使用函数指针)。假设:

MyFunc(1.23, 4.56)

我的问题是在给定此类函数对象的实例的情况下,如何匹配返回类型或参数类型?到目前为止,我提出了:

struct CMyFunObj {
    double operator ()(const double &x, const double &y);
};

哪种方法有效,但仅在第二个参数也被指定的情况下,例如致电:

template <class F, class R, class A0, class A1>
R Infer(F f, R (F::*fun)(const A0 &a0, const A1 &a1) = &F::operator ());

但如果省略第二个参数并依赖默认值则不行。有任何想法如何在C ++ 03中做到这一点?

3 个答案:

答案 0 :(得分:2)

在C ++ 03中,您无法真正推断出类似的类型(除非您想使用类似typeof),因此您必须实际提供它:

struct CMyFunObj {
    typedef double result_type;
    double operator()(const double &x, const double &y);
};

现在您可以使用其他信息:

template <class F, class A0>
CMyWrapper<typename F::result_type, F, A0>
SupplyConstArg(F f, A0 const& a0) {
    return CMyWrapper<typename F::result_type, F, A0>(f, a0);
}

SupplyConstArg(CMyFunObj(), 4.0)(5.0);

您不需要A1中的CMyWrapper类型,它可以是operator()上的模板参数。

答案 1 :(得分:1)

我不确定我是否有这个问题,但可能你的意思是这样的?

struct X {};
struct Y {};

template <class R, class A0, class A1, class F, R(F::*)(const A0 &, const A1 &) = &F::operator()>
void Infer(F f) { }

struct S {
    void operator()(const X &, const Y &) { }
    void foo(const X &, const Y &) { }
};

int main() {
    Infer<void, X, Y>(S{});
    Infer<void, X, Y, S, &S::foo>(S{});
}

从评论中可以看出,这应该适用于C ++ 03:

struct X {};
struct Y {};

template <class R, class A0, class A1, class F>
void Infer(F f, R(F::*ptr)(const A0 &, const A1 &)) { (f.*ptr)(A0(), A1()); }

template<class F>
void Infer(F f) {
    Infer(f, &F::operator());
}

struct S {
    void operator()(const X &, const Y &) { }
    void foo(const int &, const char &) { }
};

int main() {
    Infer(S());
    Infer(S(), &S::foo);
}

这样,您既可以指定要调用的方法,也可以依赖于显式将其作为参数推送的中间函数。

答案 2 :(得分:1)

您可以简单地使用中间函数:

template <class F, class R, class A0, class A1>
void Infer(F f, R (F::*fun)(const A0 &a0, const A1 &a1));

template <class F>
void Infer(F f) {
    Infer(f, &F::operator());
}

Infer(CMyFunObj());

如果您需要推断类型,可以执行as Barry says,如果您不想修改您的仿函数,则可以使用外部帮助程序类:

template <class U>
struct result_type;

template <typename F>
typename result_type<F>::type Infer(F f) {
    return Infer(f, &F::operator());
}

然后是:

struct CMyFunObj {
    double operator ()(const double& x, const double& y) { return x + y; }
};

template <>
struct result_type<CMyFunObj> {
    typedef double type;
};