如何在std ::函数参数中使用lambda推导模板类型? [英] How to have template type deduced in std::function arguments with lambda?

查看:116
本文介绍了如何在std ::函数参数中使用lambda推导模板类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个boost ::变体,我想执行函数只有当变体是一个特殊的类型,所以我修改了这个函数:

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

这很好,但我想要类型T以便我可以写成:

  if_init(b,[](double var){std :: cout <<我加倍并设置<< std :: endl;}); 

但不推演类型:

  type_inference.cpp:19:5:错误:没有匹配的函数调用'if_init'
if_init(b,[](double var){std :: cout< <我是double并设置<< 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< :: endl;}); 

它工作得很好。



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



我使用的是CLang 3.2。



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

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

typedef boost :: variant< int,double>测试;

template< typename T,typename Variant>
void if_init(Variant& opt_variant,std :: function< void(T)> functor){
if(auto * ptr = boost :: get& b $ b 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;
}


解决方案

code> 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> 不会强制执行以下任一:虽然显然你会结束编译错误,这不是一个好的。它计划改变(也许你的实现有),但改为一种不同的错误。



我个人使用模板别名(在模板参数列表),以文档和强制函子应该符合。结果如下:

  // long l = std :: forward< Functor>(functor)(42。)
//应该是有效的表达式 - 返回int的函子将
//也接受。
//触发一个硬错误(通常是一个带有好消息的static_assert)
//违反。
template< typename Functor,Requires< is_callable< Functor,long(double)>> ...>
R foo(Functor functor);

//此函数模板仅参与重载解析的文档
//如果函子符合签名。
//不触发硬错误(由设计需要);如果一切都正确,
//,那么应该拾取另一个重载 - 否则产生
//'没有匹配的重载发现'的错误
template< typename Functor,EnableIf< is_callable< Functor,long(double)>> ...>
R bar(Functor functor);

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


I have a boost::variant and I would like to execute a functor only if the variant is of a special type, so I made up this function:

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

This works well, but I would like the type T to be deduced, so that I can write that:

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

But the type is not deduced:

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 I write:

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

it works well.

Is there a way to have type T being deduced ? I would like to type T only once. Here the type is short, but in the real case, there are long types.

I'm using CLang 3.2.

Here is the full test case (the first call compiles not the second):

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

解决方案

I recommend you think of std::function<Sig> as a container of any one functor that conforms to Sig as a signature -- and which can be replaced at any moment. This functionality comes in very handy for e.g. std::vector<std::function<Sig>> because such a container can then hold functors of different types.

In your case, because you only care to have just the one functor you really don't need the functionality of std::function<Sig>. As such, I recommend you declare your function template like so:

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

If you are worried that this doesn't communicate that Functor must conform to a void(T) signature, please note that std::function<Sig> does not enforce that either: although obviously you will end up with a compilation error, it is not a nice one. It's planned to be changed (and maybe your implementation has that either), but changed to a different kind of error. Still not that helpful for your case.

I personally make use of template aliases (in the template parameter list) to both document and enforce what a functor should conform to. This ends up looking like:

// 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);

As to your exact question, the rules of C++ do not allow for a template parameter to be deduced in your case. It's really not an easily fixed 'problem', if it is one. You can find more information on this.

这篇关于如何在std ::函数参数中使用lambda推导模板类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆