2011-10-06 43 views
5

我目前正在做模板函数的一些练习。 我有任务写一个变换算法的实现。 我做到了像下面和它的作品:lambda与模板

template <class in, class out, class T> 
out stransform(in b, in e, out d, T p(const T&)) { 
    while (b != e) 
     *d++ = p(*b++); 
    return d; 
} 

与正常转换我有打电话给谓语用一个明确的类型一样

stransform(begin(vec1), end(vec1), back_inserter(vec2), predi<double>); 

现在,我偶然发现了C++ 11 Lambdas,并想打电话给我这样的功能:

stransform(begin(vec1), end(vec1), back_inserter(vec2), [] (double x) ->double {return x * 10;}); 

因此,我得到一个编译器错误,类型不能被推断。 这是我不明白的事情,因为我在我的lambda中实际上定义了两次T型。

我也检查过它正在工作的原始转换函数。然后我检查了那个的implementation,它显然是用一个模板类来实现整个功能的。 这是用模板实现谓词的正确方法吗?

回答

13

谓语通常是一个简单的模板参数:

template <class in, class out, class UnaryPredicate> 
out stransform(in b, in e, out d, UnaryPredicate p); 

这将接受指针的功能,lambda表达式和函数对象。

+0

在阅读转换的实现之后,我这么认为,这也使得它变得更容易。我仍然想知道为什么我不在其他情况下工作。 – inf

+5

@bamboon我猜是因为一个lambda函数不是函数,而是一个函数对象,因为它也可以保持状态(它是一个闭包,而不仅仅是一个函数)。 –

+1

请注意,不执行任何捕获的lambda可转换为普通函数(指针)。 – spraff

2

T p(const T&)是以参考文献为参考的T的函数的类型。你的lambda采用的值

stransform (
    begin (vec1), 
    end (vec1), 
    back_inserter (vec2), 
    [] (const double & x) -> double { 
     return x * 10; 
    }); 

这应该有效。不执行任何捕获的lambda可转换为普通函数。

+1

但为什么依赖于不必要的函数指针转换,当你可以重新定义函子来使用函子以及函数指针? – jalf

+0

不适用于我(使用msvc2011)。 – inf

+0

@jalf我同意,重新定义仿函数是一个更好的解决方案。如果这个问题是由不可变的库代码引起的,那么转换就可以工作。 – spraff

2

很明显是用模板类实现整个函数

轻微预留适当的术语:std::transform是一个函数模板,不是一个函数。更重要的是,在款式

template<class InputIterator, class OutputIterator, class Functor> 
OutputIterator 
transform(InputIterator begin, InputIterator end, OutputIterator out, Functor f); 

模板参数InputIteratorOutputIteratorFunctor的声明是不要求是类类型。考虑下面这个例子:

// function declaration 
int increment(int); 

int array[] = { 0, 1, 2, 3, 4 }; 
transform(std::begin(array), std::end(array), std::begin(array), increment); 

然后InputIteratorOutputIterator被推断为int*Functorint(*)(int)其中没有是一个类类型 - 更不用说一个模板类,但我离题。而事实上,transform也可以同样被宣布

template<typename InputIterator, typename OutputIterator, typename Functor> 
OutputIterator 
transform(InputIterator begin, InputIterator end, OutputIterator out, Functor f); 

在此,关键字typename是在模板参数的性质更清楚一点:他们是类型,任何性质的。