【问题标题】:Get lambda parameter type获取 lambda 参数类型
【发布时间】:2012-01-03 11:48:51
【问题描述】:

我想要一些方法来获取 lambda 函数的第一个参数类型,这可能吗?

例如

代替:

template<typename T>
struct base
{
     virtual bool operator()(T) = 0;
}

template<typename F, typename T>
struct filter : public base<T>
{
     virtual bool operator()(T) override {return /*...*/ }
};

template<typename T, typename F>
filter<T> make_filter(F func)
{
      return filter<F, T>(std::move(func));
}

auto f = make_filter<int>([](int n){return n % 2 == 0;});

我想要:

template<typename F>
struct filter : public base<typename param1<F>::type>
{
     bool operator()(typename param1<F>::type){return /*...*/ }
};

template<typename F>
filter<F> make_filter(F func)
{
      return filter<F>(std::move(func));
}

auto f = make_filter([](int n){return n % 2 == 0;});

根据 Xeo 的回答,这就是我在 VS2010 中所做的工作:

template<typename FPtr>
struct arg1_traits_impl;

template<typename R, typename C, typename A1>
struct arg1_traits_impl<R (C::*)(A1)>{typedef A1 arg1_type;};

template<typename R, typename C, typename A1>
struct arg1_traits_impl<R (C::*)(A1) const>{typedef A1 arg1_type;};

template<typename T>
typename arg1_traits_impl<T>::arg1_type arg1_type_helper(T);

template<typename F>
struct filter : public base<typename std::decay<decltype(detail::arg1_type_helper(&F::operator()))>::type>
{
    bool operator()(typename std::decay<decltype(detail::arg1_type_helper(&F::operator()))>::type){return /*...*/ }
};

template<typename T, typename F>
filter<F> make_filter(F func)
{
      return filter<F>(std::move(func));
}

我尝试过简化代码,但任何尝试似乎都会破坏它。

【问题讨论】:

  • 我在看std::fuction::first_argument_type 的一些技巧,但是VS2010 似乎没有实现first_argument_type
  • 复杂。 非常复杂,尤其是没有可变参数模板和VS2010。您将需要某种函数特征,将函数指针的实际类型分解为其组件并使用function_traits&lt;decltype(&amp;F::operator())&gt;::param1_type 等。不过 VS2010 的代码有问题,让我看看我是否能找到关于它的问题...
  • 您不能为此使用std::function&lt;F&gt;,因为F 是lambda 类型,而不是像bool(int) 这样的签名。
  • 我很好奇:为什么过滤器需要知道函数的参数?你不能用可变参数写一个通用的完美转发函数吗?
  • 因为 filter 有一个方法,例如operator()(T) 需要知道参数类型。

标签: c++ visual-studio-2010 templates c++11 typetraits


【解决方案1】:

最简单的选项是让operator()本身成为一个模板:

template<typename F>
struct filter
{
     template<class Arg>
     void operator(Arg&& arg){
       // use std::forward<Arg>(arg) to call the stored function
     }
};

template<typename F>
filter<F> make_filter(F func)
{
      return filter<F>(std::move(func));
}

auto f = make_filter([](int n){return n % 2 == 0;});

现在,理论上,下面的代码应该正常工作。但是,由于一个错误,它不适用于 MSVC10:

#include <iostream>
#include <typeinfo>
 
template<class FPtr>
struct function_traits;
 
template<class T, class C>
struct function_traits<T (C::*)>
{
    typedef T type;
};
 
template<class F>
void bar(F f){
  typedef typename function_traits<
      decltype(&F::operator())>::type signature;
  std::cout << typeid(signature).name();
}
 
int main(){
    bar([](int n){ return n % 2 == 0; });
}

Here 是一个关于 GCC 外观的示例。然而,MSVC10 根本不编译代码。有关详细信息,请参阅this question of mine。基本上,MSVC10 不会将 decltype(&amp;F::operator()) 视为依赖类型。这是在chat discussion 中设计的解决方法:

#include <iostream>
#include <typeinfo>
#include <type_traits>

template<class FPtr>
struct function_traits;

template<class R, class C, class A1>
struct function_traits<R (C::*)(A1)>
{   // non-const specialization
    typedef A1 arg_type;
    typedef R result_type;
    typedef R type(A1);
};

template<class R, class C, class A1>
struct function_traits<R (C::*)(A1) const>
{   // const specialization
    typedef A1 arg_type;
    typedef R result_type;
    typedef R type(A1);
};

template<class T>
typename function_traits<T>::type* bar_helper(T);

template<class F>
void bar(F f){
  typedef decltype(bar_helper(&F::operator())) fptr;
  typedef typename std::remove_pointer<fptr>::type signature;
  std::cout << typeid(signature).name();
}

int main(){
    bar([](int n){ return n % 2 == 0; });
}

【讨论】:

  • 太棒了!但是,如果 filter::operator() 是虚拟的呢?
  • @ronag:那你就有问题了。 :|如果类本身是在函数/仿函数类型上模板化的,为什么还需要virtual
  • 因为这是一个简化的例子,而且在我的真实代码中过滤器有一个基类。
  • @ronag:得出的结论是你基本上被 MSVC10 搞砸了。 :|
  • @ronag:FWIW,我终于开始实际提交a bug report to Microsoft
猜你喜欢
  • 2012-06-18
  • 1970-01-01
  • 1970-01-01
  • 2019-09-03
  • 1970-01-01
  • 2017-05-17
  • 1970-01-01
  • 1970-01-01
  • 2013-08-15
相关资源
最近更新 更多