这个问题在这里已有答案:
说明:
当我将lambda编写为以lambda作为参数的泛型函数的参数时,CLion和它的标准编译器给出了一个错误,即“候选模板被忽略”。这个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)>'
} );
提前致谢!
正如@cpplearner在上面的评论中已经指出的那样,这里不起作用的原因在这里详细解释:Constructing std::function argument from lambda。
如果你的序列已经是一个模板,那么就没有理由要求你的map
函数的callable以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;
}
忽略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;
}
(注意:代码未经测试)。
你也可以推断A
,没有std::function
演绎指南(所以在C ++ 17之前),正如迈克尔肯泽尔所建议的那样。