如何为通用lambda参数定义模板参数? [重复]

问题描述 投票:1回答:2

这个问题在这里已有答案:

说明:

当我将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)>'
     } );

提前致谢!

c++ templates lambda c++17 template-deduction
2个回答
1
投票

正如@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;
}

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;
}

(注意:代码未经测试)。

你也可以推断A,没有std::function演绎指南(所以在C ++ 17之前),正如迈克尔肯泽尔所建议的那样。

© www.soinside.com 2019 - 2024. All rights reserved.