C++构造自动推导模板类型的function adaptor(STL Function Adaptor)

deltamaster posted @ Nov 30, 2013 02:55:34 PM in C++ with tags c++ template STL lambda adaptor , 5398 阅读

继续前一篇文章http://deltamaster.is-programmer.com/posts/41833.html关于构造function adaptor的话题。

template <typename operation>
operation derivative_functor(operation f, typename operation::argument_type dx)
{
	typedef typename operation::argument_type T;
	return [=](T x)->T {
		return (f(x + dx) - f(x)) / dx;
	};
}

这是前一篇文章最后构造的function adaptor。回忆一下,尽管我们不再需要在调用时指定lambda表达式的参数类型T,但是我们仍然需要指定operation的类型。从C++语法上讲,函数模板的调用应该是支持类型推导的,也就是说,如果调用derivative_functor的时候,没有指定operation的类型,C++编译时也会自动推导。可惜这种情况下自动推导的结果是错误的,以至于无法通过编译。

再看一下调用语句。

	typedef function<double (double)> operation;
	cout << derivative_functor<operation>(my_sqr_functor<double>(), 0.000001)(5) << endl;

在这里我们给出的参数是my_sqr_functor<double>(),那么经过自动推导得到的operation类型就是my_sqr_functor<double>,尽管这个lambda表达式和my_sqr_functor<double>都分别兼容于类型function<double (double)>,但是它们两者之间没有继承关系,因此难以完成转换。

为了解决这个问题,我们就要避免出现这种不兼容的类型转换,只管的解决办法就是,令这个adaptor返回另一种类型的对象(而不是lambda表达式),这种对象的类型与operation指定的类型类似,并且同样可以像函数一样使用,兼容function<T (T)>类型。到这里我们必须要放弃lambda表达式,而用functor来模拟这个lambda表达式的行为了。

首先刚才说到,operation的类型和adaptor的返回类型有共性,下面让我们来构造这个共性的部分。

template<typename Arg, typename Result>
class my_unary_function
{
public:
	typedef Arg argument_type;
	typedef Result result_type;
private:
	virtual Result operator()(Arg arg) = 0;
};

这两者都可以当做一元函数来使用,并且我们用typedef定义了argument_type和result_type了,关于这个typedef的使用前一篇已经有一些说明。

template<typename T>
class my_sqr_functor_derived : public my_unary_function<T, T>
{
public:
	T operator()(T x)
	{
		return (x * x);
	}
};

这个求平方的functor应该继承自这个my_unary_function,因为它“是”一个一元函数,这个继承关系会将父类的typedef一并继承下来。子类的T的实际类型会被代入父类my_unary_function的Arg和Result,成为自己的argument_type和result_type。

接下来就是重点的adaptor本身的改造了。

template <typename operation>
class derivative_functor_derived
	: public my_unary_function<typename operation::argument_type, typename operation::result_type>
{
private:
	operation op;
	typename operation::argument_type dx;
public:
	derivative_functor_derived(operation f, typename operation::argument_type x)
		: op(f), dx(x) {}
	typename operation::result_type operator()(typename operation::argument_type x)
	{
		return (op(x + dx) - op(x)) / dx;
	}
};

首先这个adaptor现在是一个对象,它也“是”一个一元函数,因此同理,也继承自my_unary_function,并且指定恰当的模板参数。两个private对象,op和dx,就是先前lambda表达式中,从函数scope中传递下来的f和dx,我们在构造这个对象的时候,通过构造函数,将我们指定的op和dx保存到本对象的数据成员中,在括号运算符重载函数中,就可以使用op和dx了。至此,我们的adaptor是一个具有一元函数性质的对象,可以直接使用,而避免了不兼容类型的转换。

等一下!C++的语法不支持类模板的类型推导,这意味着我们调用这个构造函数的时候还是必须要指定的,像下面这样。

cout << derivative_functor_derived<my_sqr_functor_derived<double> >(my_sqr_functor_derived<double>(), 0.000001)(5) << endl;

我们刚才消除不兼容的类型转换,是为了省去模板参数的指定!别担心,注意到现在模板参数和传递的参数类型已经一致了吗?那现在我们只需要一个wrapper函数来帮助我们完成心愿。

template <typename operation>
derivative_functor_derived<operation> derivative_functor_derived_wrapper(operation f, typename operation::argument_type dx)
{
	return derivative_functor_derived<operation>(f, dx);
}

这个函数所做的唯一的事情,就是调用了derivative_functor_derived的构造函数,不过因为这是一个函数模板,根据我们传递的f参数类型,就可以自动推导正确的operation类型了!

cout << derivative_functor_derived_wrapper(my_sqr_functor_derived<double>(), 0.000001)(5) << endl;

这里就是最终形式了。回想上一篇开头的STL Function Adaptor调用,看看是不是有些类似呢?

cout << count_if(v.begin(), v.end(), bind2nd(less<int>(), 12)) << endl;

我们的derivative_functor_derived_wrapper和STL函数模板bind2nd的行为完全一致。这就是STL Function Adaptor的实现原理。

至此,我们了解了STL Function Adaptor的设计思想和实现,并且能够使用functor来模拟一些lambda表达式的行为。

* 本文在CC BY-SA(署名-相同方式共享)协议下发布。
AP SSC Assignment Mo 说:
Sep 09, 2022 09:44:56 PM

Department of Government Examinations and Secondary Education Board Andhra Pradesh has conducted the Assignment Exams multiple times in the academic year in Session-1 and Session-2 (Term-1 & Term-2). There are four exams are conducted Assignment-1, Assignment-2, Assignment-3 and Assignment-4. AP SSC Assignment Model Paper Every Class 10th Standard Student Studying in Government & Private Schools in Telugu Medium, English Medium & Urdu Medium can download the AP 10th Assignment Model Paper 2023 with answer solutions for theory, objective and bit questions. Subject experts of the board have designed and introduced the practice question bank for all Part-A, Part-B, Part-C, and Part-D exams.

reese 说:
Nov 30, 2022 07:58:15 PM

C++ constructs a function adapter (STL Function Adaptor) that automatically deduces the template type. This is incredibly useful when buy homes Glenville working with template libraries, as it allows for greater flexibility and easier code reuse.


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter