说明:
CLion及其标准编译器给我一个错误,当我为以lambda作为参数的泛型函数编写lambda作为参数时,“忽略了[候选模板]”。
此lambda采用通用类型T
,并返回另一个未知类型A
。
我正在编写的容器类应该支持诸如Scala中的功能操作或Java Stream API中的功能操作。
确切地说:
地图功能带来了巨大的问题。它在名为Sequence的类中作为成员函数实现,该类采用通用参数T
。
应该采用一个已知类型T
的元素(实际上会遍历整个序列)并将其转换为未知类型A
。
实现本身不是问题,但是我无法使用我知道的lambda语法调用该函数。
代码:
Sequence.h
template< typename T >
class Sequence {
public:
template< typename A >
auto map( std::function< A( const T ) > function ) const {
auto sequence = new Sequence< A >;
for ( const T& element : *this ) {
sequence->push( function( element ) );
}
return *sequence;
}
}
main.cpp
int main() {
Sequence< uint32_t > a;
a.push( 20 );
a.push( 30 );
a.push( 40 );
a.map( []( uint32_t c ) -> uint32_t {
return c * c;
} );
return 0;
}
据我了解,lambda已初始化,
接受类型为std::uint32_t
的参数,并返回类型为std::uint32_t
的值。
到目前为止,通用参数A
似乎还没有得出。
错误堆栈:
main.cpp:21:7: error: no matching function for call to 'Sequence<unsigned int>::map(main()::<lambda(uint32_t)>)'
} );
Sequence.h:143:10: note: candidate: template<class A> auto Sequence<T>::map(std::function<A(T)>) const [with A = A; T = unsigned int]
auto map( std::function< A( const T ) > function ) const {
note: template argument deduction/substitution failed:
main.cpp:21:7: note: 'main()::<lambda(uint32_t)>' is not derived from 'std::function<A(unsigned int)>'
} );
谢谢!
答案 0 :(得分:2)
忽略const
问题,您遇到了种鸡与蛋的问题。
确实可以将您的lambda转换为std::function<std::uint32_t(std::unit32_t)>
。
但是lambda不是std::function<std::uint32_t(std::unit32_t)>
也是正确的,因此编译器无法推断A
。
如果编译器无法推论A
,就不能将lambda转换为std::function<A(T)>
。
您显然可以显式地调用std::function
的正确map()
a.map(std::function<std::uint32_t(std::uint32_t)>{[]( uint32_t c ) -> uint32_t {
return c * c;
}});
,并算出您正在使用C ++ 17(因此您可以使用std::function
的推导指南)还推导std::function
的模板参数
a.map(std::function{[]( uint32_t c ) -> uint32_t {
return c * c;
}});
但是,再次使用std::function
的模板推导指南,编写mat()
接受一个简单的可调用对象并从中推导A
怎么办?
我的意思是……怎么办?
template <typename F>
auto map( F && func ) const {
using A = typename decltype(std::function{std::forward<F>(func)})::result_type;
auto sequence = new Sequence< A >;
for ( const T& element : *this ) {
sequence->push( std::forward<F>(func)( element ) );
}
return *sequence;
}
(警告:代码未经测试)。
如迈克尔·肯泽尔(Michael Kenzel)的建议,您还可以推导A
,而无需std::function
推导指南(在C ++ 17之前)。
答案 1 :(得分:1)
正如@cpplearner在上面的评论中已经指出的那样,在Constructing std::function argument from lambda中对此进行了详细说明。
如果Sequence已经是模板,则没有理由要求将map
函数的可调用对象以std::function
的形式传递。至少,我似乎无法提出可以证明这样做的理由。 std::function
通常不能随意构造或调用,并且也可以禁止内联。除非您确实需要存储任意可调用对象以供以后使用的能力,否则最好避免使用它。只需获取转发参考,例如:
template <typename F>
auto map(F&& f) const;
您应该能够推断出在序列元素上调用f
的任何结果类型,例如通过
decltype(f(std::declval<T>()))
此外,不要仅仅返回指向新Sequence
的原始指针。使用std::unique_ptr
。
将所有内容放在一起,您的map
函数可能看起来像这样:
template <typename F>
auto map(F&& f) const
{
using output_element_type = decltype(f(std::declval<T>()));
auto sequence = std::make_unique<Sequence<output_element_type>>();
for (const T& element : *this)
sequence->push(f(element));
return sequence;
}