Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/149.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.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++ 在C++;0x_C++_Templates_Lambda_C++11_Specialization - Fatal编程技术网

C++ 在C++;0x

C++ 在C++;0x,c++,templates,lambda,c++11,specialization,C++,Templates,Lambda,C++11,Specialization,我已经编写了一个traits类,它允许我在C++0x(使用GCC4.5.0测试)中提取有关函数或函数对象的参数和类型的信息。一般情况下处理函数对象: template <typename F> struct function_traits { template <typename R, typename... A> struct _internal { }; template <typename R, typename... A>

我已经编写了一个traits类,它允许我在C++0x(使用GCC4.5.0测试)中提取有关函数或函数对象的参数和类型的信息。一般情况下处理函数对象:

template <typename F>
struct function_traits {
    template <typename R, typename... A>
    struct _internal { };

    template <typename R, typename... A>
    struct _internal<R (F::*)(A...)> {
        // ...
    };

    typedef typename _internal<decltype(&F::operator())>::<<nested types go here>>;
};
这里的问题是
函数特性的专门化都不适用。C++0x草案说表达式的类型是“唯一的、未命名的、非并集类类型”。在表达式中调用<代码> Type ID(…).NAMEL()/CODE的结果使我看到了GCC的内部命名约定,lambda,<代码>主体:{lambda(int)1 } < /> >,而不是语法上表示C++类型名的东西。

简而言之,我可以在模板中添加以下内容:

template <typename R, typename... A>
struct function_traits<????> { ... }
模板
结构函数{…}

这将允许这个traits类接受lambda表达式?

我认为可以专门化lambda的traits,并对未命名函子的签名进行模式匹配。下面是在g++4.5上运行的代码。尽管有效,但lambda上的模式匹配似乎与直觉相反。我有很多评论

foo([](int x) { ... });
struct X
{
  float operator () (float i) { return i*2; }
  // If the following is enabled, program fails to compile
  // mostly because of ambiguity reasons.
  //double operator () (float i, double d) { return d*f; } 
};

template <typename T>
struct function_traits // matches when T=X or T=lambda
// As expected, lambda creates a "unique, unnamed, non-union class type" 
// so it matches here
{
  // Here is what you are looking for. The type of the member operator()
  // of the lambda is taken and mapped again on function_traits.
  typedef typename function_traits<decltype(&T::operator())>::return_type return_type;
};

// matches for X::operator() but not of lambda::operator()
template <typename R, typename C, typename... A>
struct function_traits<R (C::*)(A...)> 
{
  typedef R return_type;
};

// I initially thought the above defined member function specialization of 
// the trait will match lambdas::operator() because a lambda is a functor.
// It does not, however. Instead, it matches the one below.
// I wonder why? implementation defined?
template <typename R, typename... A>
struct function_traits<R (*)(A...)> // matches for lambda::operator() 
{
  typedef R return_type;
};

template <typename F>
typename function_traits<F>::return_type
foo(F f)
{
  return f(10);
}

template <typename F>
typename function_traits<F>::return_type
bar(F f)
{
  return f(5.0f, 100, 0.34);
}

int f(int x) { return x + x;  }

int main(void)
{
  foo(f);
  foo(X());
  bar([](float f, int l, double d){ return f+l+d; });
}
struct X
{
浮点运算符()(浮点i){return i*2;}
//如果启用以下选项,则程序无法编译
//主要是因为模棱两可的原因。
//双运算符()(float i,double d){返回d*f;}
};
模板
当T=X或T=lambda时,结构函数_//匹配
//正如所料,lambda创建了一个“唯一的、未命名的非并集类类型”
//所以它在这里匹配
{
//下面是您要查找的内容。成员运算符()的类型
//取lambda的值并再次映射到函数_特征上。
typedef typename函数_traits::return_type return_type;
};
//与X::operator()匹配,但与lambda::operator()不匹配
模板
结构功能特性
{
类型def R return_type;
};
//我最初认为上面定义的成员函数是专门化的
//该特征将匹配lambdas::operator(),因为lambda是一个函子。
//但事实并非如此。相反,它与下面的匹配。
//我想知道为什么?实现定义?
模板
lambda::operator()的结构函数\特征//匹配项
{
类型def R return_type;
};
模板
typename函数\特性::返回\类型
傅(女)
{
返回f(10);
}
模板
typename函数\特性::返回\类型
巴(F)
{
返回f(5.0f,100,0.34);
}
intf(intx){返回x+x;}
内部主(空)
{
傅(f);
foo(X());
条([](浮点f,整数l,双d){返回f+l+d;});
}

通过将部分工作委托给一系列函数模板而不是类模板,您可以提取相关信息

首先,我应该说,对于lambda(对于非捕获、非泛型、非可变的
lambda),相关的方法是
const
方法。因此,您将无法区分真正的lambda和以下两者之间的区别:

struct {
    int operator() (int) const { return 7; }
} object_of_unnamed_name_and_with_suitable_method;
因此,我必须假设您不想对lambda进行“特殊处理”,也不想测试一个类型是否为lambda类型,而是只想为任何足够简单的对象提取返回类型和所有参数的类型。例如,我所说的“足够简单”是指
操作符()
方法本身不是模板。另外,作为额外信息,一个布尔值告诉我们是否存在并使用了
操作符()
方法,而不是普通的旧函数



//首先,一个方便的结构,用于存储所有结果:
模板
结构函数\u特性\u结果{
constexpr static bool is_method=is_method;
constexpr static bool is_const_method=is_const_method;
typedef C class_type;//对于普通函数为void。否则,
//函子/lambda类型
类型def R return_type;
typedef元组args_type_as_元组;
};
//这将从方法签名中提取所有详细信息:
模板
结构中间步骤;
模板
结构中间步骤//非常量方法
:公共功能\u特征\u结果
{
};
模板
结构中间步骤//常量方法
:公共功能\u特征\u结果
{
};
//接下来的两个重载完成了分离的初始任务
//带::运算符()的函子的普通函数指针
模板
功能特性结果
功能特征辅助(R(*)(Args…);
模板
中间步骤
功能(特征)(F),;
//最后,实际的'function\u traits'结构
//一切都交给帮手
模板
结构函数特征:公共decltype(函数特征辅助对象(declval())
{
};

这个
void\t
技巧会有帮助

除非您有C++17,否则需要包含
void\t
的定义:

template<typename... Ts> struct make_void { typedef void type;};
template<typename... Ts> using void_t = typename make_void<Ts...>::type;
简单函数的traits对象与您已有的相同:

template <typename R, typename... A>
struct function_traits<R (*)(A...)>
{
    using return_type = R;
    using class_type  = void;
    using args_type   = std:: tuple< A... >;
};
最后,重要的特点。给定一个类类型,包括lambda类型,我们希望从
T
转发到
decltype(&T::operator())
。我们希望确保此特性仅适用于类型
T
,其中
::operator()
可用,这就是
void\u T
为我们所做的。要强制执行此约束,我们需要将
&T::operator()
放在trait签名的某处,因此
模板结构函数\u traits
:公共函数\u traits
{
};
(非
mutable
,非泛型)lambdas中的运算符()方法是
const
,这解释了为什么我们需要上面的
const
模板


但最终这是非常严格的。这不适用于通用lambda,也不适用于带有模板化
操作符()
的对象。如果你重新考虑你的设计,你会发现一种更灵活的不同方法。

不。你为什么认为你需要这样的东西?我认为我的例子给出了一个不错的用例:如果我有一个接受函数或函数对象的通用算法,我可以使用这个特性cla
// First, a convenient struct in which to store all the results:
template<bool is_method_, bool is_const_method_, typename C, typename R, typename ...Args>
struct function_traits_results {
    constexpr static bool is_method = is_method_;
    constexpr static bool is_const_method = is_const_method_;
    typedef C class_type; // void for plain functions. Otherwise,
                          // the functor/lambda type
    typedef R return_type;
    typedef tuple<Args...> args_type_as_tuple;
};

// This will extract all the details from a method-signature:
template<typename>
struct intermediate_step;
template<typename R, typename C, typename ...Args>
struct intermediate_step<R (C::*) (Args...)>  // non-const methods
    : public function_traits_results<true, false, C, R, Args...>
{
};
template<typename R, typename C, typename ...Args>
struct intermediate_step<R (C::*) (Args...) const> // const methods
    : public function_traits_results<true, true, C, R, Args...>
{
};


// These next two overloads do the initial task of separating
// plain function pointers for functors with ::operator()
template<typename R, typename ...Args>
function_traits_results<false, false, void, R, Args...>
function_traits_helper(R (*) (Args...) );
template<typename F, typename ..., typename MemberType = decltype(&F::operator()) >
intermediate_step<MemberType>
function_traits_helper(F);


// Finally, the actual `function_traits` struct, that delegates
// everything to the helper
template <typename T>
struct function_traits : public decltype(function_traits_helper( declval<T>() ) )
{
};
template<typename... Ts> struct make_void { typedef void type;};
template<typename... Ts> using void_t = typename make_void<Ts...>::type;
template <typename T, typename = void>
struct function_traits;
template <typename R, typename... A>
struct function_traits<R (*)(A...)>
{
    using return_type = R;
    using class_type  = void;
    using args_type   = std:: tuple< A... >;
};
template <typename R, typename... A>
struct function_traits<R (C::*)(A...)>
{
    using return_type = R;
    using class_type  = void;
    using args_type   = std:: tuple< A... >;
};
template <typename R, typename C, typename... A>
struct function_traits<R (C::*)(A...) const> // const
{
    using return_type = R;
    using class_type  = C;
    using args_type   = std:: tuple< A... >;
};
template <typename T>
struct   function_traits<T, void_t< decltype(&T::operator()) > > 
: public function_traits<           decltype(&T::operator())   >
{
};