Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/136.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用参数包将lambda强制转换为std::函数_C++_Lambda_Variadic Templates_C++17 - Fatal编程技术网

C++ 使用参数包将lambda强制转换为std::函数

C++ 使用参数包将lambda强制转换为std::函数,c++,lambda,variadic-templates,c++17,C++,Lambda,Variadic Templates,C++17,关于将lambda强制转换为std::functions有几个问题,但是我还没有看到一个使用参数包作为参数列表的问题。在我的g++(7.1.1-4)版本中,这似乎被破坏了,可能只是不受支持。那么这是合法的c++17(按标准)?若否,原因为何 #include <functional> template <typename TReturn, typename ... TArgs> void Functor(std::function<TReturn (TArgs..

关于将lambda强制转换为
std::function
s有几个问题,但是我还没有看到一个使用参数包作为参数列表的问题。在我的g++(7.1.1-4)版本中,这似乎被破坏了,可能只是不受支持。那么这是合法的c++17(按标准)?若否,原因为何

#include <functional>

template <typename TReturn, typename ... TArgs>
void Functor(std::function<TReturn (TArgs...)> f) {}

int main(int argc, char * argv[]) {
    auto x = [] (int a, int b) { return a * b; };
    Functor<int, int, int>(x);
    return 0;
}
这失败了:

#include <functional>

template <typename TReturn, typename ... TArgs>
void Functor(std::function<TReturn (TArgs...)> f) {}

int main(int argc, char * argv[]) {
    auto x = [] (int a, int b) { return a * b; };
    Functor<int, int, int>(x);
    return 0;
}
这不会编译,因为lambda不是
std::function
(或派生自lambda的函数),这与不提供任何类型就无法调用它的原因相同

非变量版本没有这个问题,因为您已经提供了所有类型


但实际上,你想要的是:

template <typename F>
void Functor(F ) {}
模板
无效函子(F){}

这不会让你失去任何类型的安全。它使用的
std::function
会丢失类型信息,因为该类模板用于类型擦除。

问题是编译器不知道您打算将
int,int
作为
TArgs
的整体,因此尝试从参数
f
推断
TArgs
的其余部分

例如,这将是有效的:

Functor<int, int, int>(std::function<int(int, int, char, float)>{});
// TArgs := {int, int, [...]                       char, float}
或者您可以使用未分解的签名
Sig
编写
Functor

template <Sig>
void Functor(std::function<Sig> f) {}

下面是一个解决方案,您可以调用
functor
,而无需指定其模板参数:

#include <functional>
#include <type_traits>

template <class T> struct Fun_trait {};

template <class T, class... Args, class Ret>
struct Fun_trait<auto (T::*) (Args...) const -> Ret>
{
    using F = std::function<auto (Args...) -> Ret>;
};


template <class TReturn, class... TArgs>
void functor(std::function<TReturn (TArgs...)> f) {}

template <class F>
std::void_t<decltype(&F::operator())>
functor(F f)
{
    return functor<typename Fun_trait<decltype(&F::operator())>::F>(f);
};


int main(int argc, char * argv[])
{
    auto x = [] (int a, int b) { return a * b; };

    // nice and easy:
    functor(x); 

    return 0;
}
#包括
#包括
模板结构Fun_trait{};
模板
结构乐趣\u特质Ret>
{
使用F=std::function Ret>;
};
模板
空函子(std::函数f){}
模板
std::void\u t
函子(F)
{
返回函子(f);
};
int main(int argc,char*argv[])
{
autox=[](inta,intb){返回a*b;};
//简单明了:
函子(x);
返回0;
}
这只是一个懒散的初稿,让你开始。您需要扩展它以支持转发和非常量
操作符()


它分两个阶段工作:

首先,我们有
Fun\u trait
who-对于指针方法类型(例如lambda的
操作符()
),为所需的
std::function
参数类型定义了一个别名
F


接下来,我们有一个函数的重载
functor
,它通过SFINAE with
std::void\u t
仅适用于带有非重载
操作符()的functor(例如lambda)然后使用上面的特性调用主函数
functor
,并推导出正确的模板参数。

如果要调用
模板中的
std::function
,则将lambda强制转换为
std::function
很少是一个好主意
std::function
是类型擦除,模板类型擦除只有在您将其“传递”到其他地方并/或返回时才有意义

在任何情况下,请尝试以下方法:

template <class Sig>
void Functor(std::function<Sig> f) {}

int main(int argc, char * argv[]) {
  auto x = [] (int a, int b) { return a * b; };
  Functor<int(int, int)>(x);
  return 0;
}
模板
空函子(std::函数f){}
int main(int argc,char*argv[]){
autox=[](inta,intb){返回a*b;};
函子(x);
返回0;
}
但你真的应该这么做

template <class F>
void Functor(F f) {}
模板
无效函子(F){}
这是完全类型安全的

如果你想提前检查类型,你可以写

template<class Sig, class F>
struct signature_compatible;
template<class R, class...Args, class F>
struct signature_compatible<R(Args...), F> :
  std::is_consructible< R, std::result_of_t<F(Args...)>>
{};
模板
结构签名兼容;
模板
结构签名\u兼容:
std::是否可构造
{};
那就做吧

template <class Sig, class F>
void Functor(F f) {
  static_assert( signature_compatible<Sig, F&>::value, "bad signature" );
}
模板
虚空函子(F){
静态断言(签名兼容::值,“坏签名”);
}
但只有当你真的需要的时候

template <class Sig>
void Functor(std::function<Sig> f) {}

int main(int argc, char * argv[]) {
  auto x = [] (int a, int b) { return a * b; };
  Functor<int(int, int)>(x);
  return 0;
}
template <class F>
void Functor(F f) {}
template<class Sig, class F>
struct signature_compatible;
template<class R, class...Args, class F>
struct signature_compatible<R(Args...), F> :
  std::is_consructible< R, std::result_of_t<F(Args...)>>
{};
template <class Sig, class F>
void Functor(F f) {
  static_assert( signature_compatible<Sig, F&>::value, "bad signature" );
}