CppCon - Modern Template Metaprogramming 杂记
2014年底才看到github和channel9上有CppCon2014的视频和资料,顿时激动不已。最近小生也一直在研习CppCon2014中令人兴奋的内容。这篇鄙文就是小生学习了《Modern Template Metaprogramming》之后,有对Unevaluated Operands更深刻的理解,有感而写。
C++98标准中的Unevaluated Operands,只有sizeof操作符。C++11又引入了decltype,typeid和noexcept。Unevaluated Operands不会有求值的计算,即使是在编译期间。这意味着Unevaluated Operands中的表达式甚至不会生成具体的C++代码,操作符中的表达式仅需要声明而无需定义。在模板元编程中,我们有时候经常仅需要对catch a glimpse of一个表达式,而这些操作符都是很好的工具。
下面我们以std::is_copy_assignable为例来看看Unevaluated Operands的威力。
namespace cpp11
{
template <typename T>
struct is_copy_assignable
{
private:
template <typename U, typename = decltype(std::declval<T&>() = std::declval<T const&>())>
static std::true_type try_assign(U&&); static std::false_type try_assign(...); public:
using type = decltype(try_assign(std::declval<T>()));
};
}
我们以c++11的版本开始。这个std::is_copy_assignable的实现原理就是SFINAE。给定一个C++类型T,如果T存在一个有效的operator=,那么成员模板函数try_assign的第二个模板参数中decltype里面的表达式将是well formed,decltype将会推导出这个表达式的类型。而第二个非模板的普通成员函数try_assign的形参使用" ..." 是因为这种情况是最差匹配的情况,is_copy_assignable需要优先匹配成员模板函数try_assign。元函数返回type时,再次使用了decltype,这里是真正的点睛之笔。由于decltype无需求值,因此try_assign无需一个函数体。std::declval是C++11引入universal reference的一个附属品,它也是一个模板函数同样没有函数体,返回值的类型是一个T&&(universal reference),try_assign中使用std::declval可以让编译器知道我们传递给这个函数的参数类型,但没有真正的去构造一个对象,就好像是假设我传递一个实参给try_assign. 在Unevaluated Operands中的表达式如果是一个函数调用,那么std::declval是一个非常好的工具,姑且可以将它当做一个惯用法。那么如果这个T不存在一个有效的operator=,编译器将使用SFINAE选择普通的成员函数。最后元函数返回的type在T::operator= 存在的情况下是std::true_type,反之则是false_type.
在c++98的年代,Unevaluated Operands只有sizeof,那么怎么实现呢。同使用下面这个例子或者类似的实现方法。
namespace cpp98
{
namespace detail
{
template <typename T>
T declval();
} template <typename T>
struct is_copy_assignable
{
private: typedef char One;
typedef struct { char a[]; } Two; template <int N = sizeof(detail::declval<T&>() = detail::declval<T const&>())>
static One try_assign(int); static Two try_assign(...); public: typedef typename std::conditional<sizeof(try_assign()) == sizeof(One),
std::true_type, std::false_type>::type type;
};
}
sizeof只能推导出类型的大小,因此try_assign不能再返回std::true_type和st::false_type,而是返回了两个大小不同的类型。实现原理依旧是SFINAE,而元函数返回的类型是根据try_assign返回类型的大小来决定导出std::true_type还是std::false_type.由于cpp98没有右值引用,所以这里自己实现了一个declval的替代版。在c++98的版本中,元函数的类型计算都是由sizeof来驱动的。c++11引入了更多的非求值操作符后,元编程确实方便了不少。
在《Modern Template Metaprogramming》这篇演讲中还有一个非常有趣的模板工具,就是void_t. 它的实现可能如下代码所示
template <typename ... Args>
struct make_void
{
typedef void type;
}; template <typename ... Args>
using void_t = typename make_void<Args...>::type;
或者,
template <typename ... Args>
using void_t = void;
让我们先来看看使用void_t来实现我们的is_copy_assignable.
namespace cpp1y
{
template <typename ... Args>
struct make_void
{
typedef void type;
}; template <typename ... Args>
using void_t = typename make_void<Args...>::type; template <typename T, typename = void>
struct is_copy_assignable : std::false_type
{}; template <typename T>
struct is_copy_assignable<T, void_t<decltype(std::declval<T&>() = std::declval<T const&>())>> : std::true_type
{
};
}
利用void_t实现的版本又要比使用SFINAE的版本实现简单许多。给定一个C++类型T,传递到元函数is_copy_assignable中,由于这个版本的元函数有两个参数,那么is_copy_assignable<T>被推导为is_copy_assignable<T,void>. 接下来,编译要检查是否有more specialized的特化版本。如果T有一个有效的operator=,那么is_copy_assignable的特化版本中的第二个参数中的decltype推导的表达式是well formed,那么decltype计算类型并与void_t共同推导出void. 由于特化版本是more specialized,因此编译器选择这个特化版本,并调用元函数std::true_type。反之,如果T没有一个有效的operator=,那么decltype推导的表达式无效,因此这种情况下的is_copy_assignable没有特化版本并调用元函数std::false_type。这里要注意的是,第二个默认的模板参数必须要以void为缺省的实参类型,因为void_t实际上就是void,才能让编译器找到特化的版本。换而言之,缺省的类型要与void_t一致,如果实现一个类似的int_t,那么这个缺省的类型应该是int.
小生在MSVC12实验的void_t版本一直有问题,还有更简单版本的void_t实现在MSVC和gcc的编译器上都不对,根据这篇演讲的说法是还需要一个提案,详见CWG 1558, treatment of unused arguments in an alias template specialization. 错误都一样,无论T是否有可用的operator=,这个元函数始终选择特化版本,即都是true_type,可能是因为void_t模板没有使用任何模板参数的原因吧,还需要进一步的研究。
这是最后的实验代码和运行结果如下:
http://ideone.com/ZUCvhY
CppCon - Modern Template Metaprogramming 杂记的更多相关文章
- C++模板元编程(C++ template metaprogramming)
实验平台:Win7,VS2013 Community,GCC 4.8.3(在线版) 所谓元编程就是编写直接生成或操纵程序的程序,C++ 模板给 C++ 语言提供了元编程的能力,模板使 C++ 编程变得 ...
- Template Metaprogramming in C++
说实话,学习C++以来,第一次听说"Metaprogramming"这个名词. Predict the output of following C++ program. 1 #in ...
- 模板元编程(Template metaprogramming)
https://en.wikipedia.org/wiki/Template_metaprogramming 没看懂...只知道了模板元编程的代码是在编译期运行的... 敲了2个例子: 1. #inc ...
- C++Template 模版的本质
我想知道上帝的構思,其他的都祇是細節. ...
- Effective C++ -----条款48:认识template元编程
Template metaprogramming(TMP,模板元编程)可将工作由运行期移往编译期,因而得以实现早期错误侦测和更高的执行效率. TMP可被用来生成“基于政策选择组合”(based on ...
- 【48】认识template元编程
1.TMP(template metaprogramming),模版元编程有两个效力:第一,它让某些事情更容易:第二,可将工作从运行期转移到编译期.
- 《Effective C++》:条款48:理解力template
元编程
Template metaprogramming(TMP,模板元编程)这是写template-based C++规划.编译过程.template metaprogramming随着C++写模板程序,化 ...
- Metaprogramming
Metaprogramming https://en.wikipedia.org/wiki/Metaprogramming 元编程, 是一种编程技术, 制造的计算机程序,具有这种能力, 对待程序为他们 ...
- C++ template —— 表达式模板(十)
表达式模板解决的问题是:对于一个数值数组类,它需要为基于整个数组对象的数值操作提供支持,如对数组求和或放大: Array<), y(); ... x = 1.2 * x + x * y; 对效率 ...
随机推荐
- system进程启动普通用户进程调研
system进程启动普通用户进程 关键函数是CreateProcessAsUser 主要思路是先取得目的用户的token,然后用上面的函数启动 1.从explorer中取token BOOL GetT ...
- [QT]QT概述
QT概述 基于C++的GUI开发框架,跨平台.Qt 是一个用于桌面系统和嵌入式开发的跨平台应用程序框架. QT是挪威TROLLTECH公司开发的跨平台C++工具,在UNIX下非常出名:他的宗旨是“一次 ...
- CSSOM视图模式
相关技术文章: CSSOM视图模式(CSSOM View Module)相关整理 W3C CSSOM View Module
- MySQL中的两个时间函数,用来做两个时间之间的对比
TIMESTAMPDIFF,(如果当期时间和之前时间的分钟数相比较.大于1天,即等于1:小于1天,则等于0) select TIMESTAMPDIFF(DAY,'2016-11-16 10:13:42 ...
- 接入SDK
管理提醒: 本帖被 fm2010 设置为精华(2014-11-12) http://www.cocoachina.com/bbs/read.php?tid-239087.html 本帖属于Co ...
- NSRunLoop 详解
今天看到了NSRunloop,其实之前也有看了关于NSRunloop的内容,在这里想简单的就个人的理解总结一下.其实自己在开发的过程当中,还没有更多的涉及到NSRunloop的功能.总的来说,NSRu ...
- s3c2416裸跑环境配置
最近刚刚开始学习ARM-linux,上周买了块tq2416的板子,给的Linux资料太复杂太深奥不愿看,等不及想要把2416跑起来.于是到处找相关裸跑资料,可是用2416的人实在少,网上的资料更少,裸 ...
- VS2010中<无法打开包括文件:“iostream.h”:>错误解决方法
C/C++ code? 1 2 #include <iostream.h> 改为: C/C++ code? 1 2 #include <iostream> using name ...
- hdu 1535 Invitation Cards
http://acm.hdu.edu.cn/showproblem.php?pid=1535 这道题两遍spfa,第一遍sfpa之后,重新建图,所有的边逆向建边,再一次spfa就可以了. #inclu ...
- rsync实现文件备份同步(比如服务器镜像)
[rsync实现网站的备份,文件的同步,不同系统的文件的同步,如果是windows的话,需要windows版本cwrsync] 一.什么是rsync rsync,remote synchronize顾 ...