如何使用lambda在std :: function参数中推导出模板类型?

时间:2013-02-09 02:50:21

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

我有一个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;
}

1 个答案:

答案 0 :(得分:6)

我建议您将std::function<Sig>视为任何一个符合Sig作为签名的仿函数的容器 - 并且可以随时替换。该功能非常方便用于例如std::vector<std::function<Sig>>因为这样的容器可以保存不同类型的仿函数。

在您的情况下,因为您只关心只有一个仿函数,所以您真的不需要std::function<Sig>的功能。因此,我建议你声明你的功能模板:

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

如果您担心这不会传达Functor必须符合void(T)签名,请注意std::function<Sig> 强制执行:虽然显然你 最终会出现编译错误,但它不是一个好的。计划进行更改(也许您的实现也有),但更改为其他类型的错误。对你的案件仍然没有帮助。

我个人使用模板别名(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);

对于完全问题,C ++规则不允许在您的案例中推导出模板参数。它真的不是一个容易解决的“问题”,如果它是一个。您可以在此找到more information