您的位置:首页 > 编程语言 > C语言/C++

[C++技巧篇1]enable_if,lambda

2017-10-17 01:16 267 查看
麦片说 

各位C++的用户,是否已经开始用C++11了呢?至少也是体验过boost的吧?本文不是关于如何用的,而是总结一些小技巧。这些小技巧嘛,小麦第一次看到的时候的感受通常是。。。”我擦嘞,还能这样!!这不科学吧?!“,经过尝试,小麦发现,这。。。真的是科学的!


enable_if


http://ju.outofmemory.cn/entry/30164

这个东西出现在C++11和boost中,两者用法略有区别,本文就以C++11中的std::enable_if为例,说说这个诡异的存在。大概说来,这个东西的实现是非常简单,甚至看上去略微幼稚的
template<bool, typename _Tp = void>
struct enable_if { };
template<typename _Tp>
struct enable_if<true, _Tp>{ typedef _Tp type; };


这个东西最大的作用在于提供一些针对性的重载,当然,这需要配合一些类型判断之类的,这个技巧相信大家是能接受的,这里只说一个技巧,那就是返回值不同的重载。大家知道,重载必须是参数不同,只有返回值不同,这是不行的!但是,C++是个好语言,只要主人高兴,穿着黑丝被推倒也没关系的。。。于是,就有了这样的用法:
template <class T>
typename std::enable_if<std::is_arithmetic<T>::value, int>::type foo( T &t)
{
return static_cast<int>(t);
}
template <class T>
typename std::enable_if<std::is_class<T>::value, T>::type & foo( T &t)
{
return t;
}


这确实是重载呢,客官且看下面的例子
foo(n1);
Myclass a;
foo(a);


这两次foo调用的分别是两个不同的东西,而且,这两个东西的参数是一样的,只是返回值不一样,类似的技巧和lambda配合更是天衣无缝啊!


lambda

此等神器的出现,直接使小麦抛弃了boost和C++11中的bind,那传参,那自由,那类型推导,真是完虐bind之流啊。不知道基本用法的同志请翻手册,此文不是入门手册。下面只说一个技巧,就是小麦最喜欢的用法
template <class FT>
auto 	call(FT && f){return f();} //This is a wrong case

call([](){std::cout<<"do anything you want"<<std::endl;});


当然,上例是错误的,因为auto并不能让编译器推断出对应的类型,并且,如果是void的话,这里还不能return!当然,这是难不倒小麦的,我说过,C++是个好姑娘(语言)!首先,我们要能推断出返回值类型,这并不复杂,复杂的小麦也搞不定啊!
template<class F>
struct deduce_function{};

template<class Ret, class C, class... Args>
struct deduce_function<Ret (C::*)(Args...) const>
{
typedef std::function<Ret (Args...)> type;
typedef Ret ret_type;
};

template<class Ret, class C, class... Args>
struct deduce_function<Ret (C::*)(Args...)>
{
typedef std::function<Ret(Args...)> type;
typedef Ret		ret_type;
};

template<class F>
struct function_res_traits
{
typedef typename 	deduce_function<decltype(&std::remove_reference<F>::type::operator())>::ret_type ret_type;
};


有了返回类型,就好办多了,下面又是enable_if出场的时间了,
template<class FT>
auto  call(FT && f)
-> typename std::enable_if<std::is_void<typename function_res_traits<FT>::ret_type>::value, void>::type
{
f();
}

template<class FT>
auto  call(FT && f )
-> typename std::remove_reference<typename function_res_traits<FT>::ret_type>::type &&
{
return f();
}


就是这样,通过配合is_void判断返回类型是否为void,加上enable_if,就解决了lambda的返回值问题,实现了相同参数的重载。由于C++的故事比较丰富,所以。。。小麦下次再写吧!

下期预告:boost::function与boost::asio::yield,同样奇葩,敬请期待!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c++