【问题标题】:How to have template type deduced in std::function arguments with lambda?如何使用 lambda 在 std::function 参数中推导出模板类型?
【发布时间】:2013-01-24 22:04:17
【问题描述】:

我有一个 boost::variant,我只想在变体是特殊类型时才执行函子,所以我编造了这个函数:

template<typename T, typename Variant>
void if_init(Variant& opt_variant, std::function<void(T)> functor){
    if(auto* ptr = boost::get<T>(&opt_variant)){
        functor(*ptr);
    }   
}

这很好用,但我想推导出类型 T,以便我可以这样写:

if_init(b, [](double var){ std::cout << "I'm double and set" << std::endl; });

但是没有推导出类型:

type_inference.cpp:19:5: error: no matching function for call to 'if_init'
    if_init(b, [](double var){ std::cout << "I'm double and set" << std::endl; }); 
    ^~~~~~~
type_inference.cpp:10:6: note: candidate template ignored: failed template argument deduction
    void if_init(Variant& opt_variant, std::function<void(T)> functor){

如果我写:

if_init<double>(b, [](double var){ std::cout << "I'm double and set" << std::endl; });

效果很好。

有没有办法推导出类型 T ?我只想输入 T 一次。这里的类型很短,但在实际情况下,有长类型。

我正在使用 CLang 3.2。

这是完整的测试用例(第一个调用编译不是第二个):

#include <iostream>
#include <functional>
#include <boost/variant.hpp>

typedef boost::variant<int, double> Test;

template<typename T, typename Variant>
void if_init(Variant& opt_variant, std::function<void(T)> functor){
    if(auto* ptr = boost::get<T>(&opt_variant)){
        functor(*ptr);
    }   
}

int main(){
    Test b = 1.44; 

    if_init<double>(b, [](double var){ std::cout << "I'm double and set" << std::endl; });
    if_init(b, [](int var){ std::cout << "I'm int and set" << std::endl; });      

    return 0;
}

【问题讨论】:

    标签: c++ templates c++11 lambda type-inference


    【解决方案1】:

    我建议您将std::function&lt;Sig&gt; 视为符合Sig 作为签名的任何一个函子的容器——并且可以随时替换。此功能非常方便,例如std::vector&lt;std::function&lt;Sig&gt;&gt; 因为这样的容器可以容纳 不同 类型的函子。

    在你的情况下,因为你只关心只有一个函子,你真的不需要std::function&lt;Sig&gt; 的功能。因此,我建议您像这样声明您的函数模板:

    template<typename T, typename Variant, typename Functor>
    void if_init(Variant& opt_variant, Functor functor);
    

    如果您担心这不会表明Functor 必须符合void(T) 签名,请注意std::function&lt;Sig&gt; 确实 强制执行:虽然显然你最终导致编译错误,这不是一个好的错误。计划进行更改(也许您的实现也有),但更改为另一种错误。对您的情况仍然没有太大帮助。

    我个人使用模板别名 (in the template parameter list) 来记录和强制执行函子应符合的内容。这最终看起来像:

    // Documents that e.g. long l = std::forward<Functor>(functor)(42.)
    // should be a valid expression -- a functor that returns int would
    // also be accepted.
    // Triggers a hard-error (typically a static_assert with a nice message)
    // on violation.
    template<typename Functor, Requires<is_callable<Functor, long(double)>>...>
    R foo(Functor functor);
    
    // Documents that this function template only participates in overload resolution
    // if the functor conforms to the signature.
    // Does not trigger a hard-error (necessary by design); if everything goes right
    // then another overload should be picked up -- otherwise an error of the kind
    // 'no matching overload found' is produced
    template<typename Functor, EnableIf<is_callable<Functor, long(double)>>...>
    R bar(Functor functor);
    

    至于您的 exact 问题,C++ 的规则不允许在您的情况下推断出模板参数。这真的不是一个容易解决的“问题”,如果它是一个。您可以在此找到more information

    【讨论】:

    • 好吧,我不知道 std::function 没有强制执行 :( 但是,如果我只使用 typename Functor,它不会改变不会推导出 T 的事实对吧?
    • @BaptisteWicht 是的。在这种情况下,您可以要求 Functor 是单态的并提取其单个参数类型。这不是我通常做的事情(我真的尽量避免检查函子,因为这对多态函数不起作用)而且我不能想出一个特质来完成这项工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多