C++14模板类隐式构造/转换 无需TypeIdentity技巧实现方法
C++14模板类隐式构造/转换实现方案
问题根因
该问题本质是C++模板实参推导的规则限制:
- 模板参数推导阶段,编译器不会考虑隐式类型转换,只有推导完成后的重载决议阶段才会处理隐式转换
- 把
operator==定义为独立模板函数时,两个参数都会参与模板参数推导:当其中一个参数是const T*类型时,无法匹配const B<T>&,推导直接失败,不会触发后续的隐式构造 TypeIdentity的作用是将第二个参数放入非推导上下文,模板参数T完全由第一个参数确定,因此第二个参数可以正常触发隐式构造
无元编程依赖的实现方案
最简洁的C++14兼容方案是将operator==定义为模板类的内部友元非模板函数,示例代码如下:
#include <cassert> #include <iostream> template <typename T> struct C { C(const T *aze) { std::cout << "C<T> ctor\n"; } // 内部友元函数,不属于模板,每个C<T>实例对应一个固定参数的operator== friend bool operator==(const C& lhs, const C& rhs) { std::cout << "C<T>==C<T>\n"; return true; } }; // 不需要额外的TypeIdentity定义,也不需要写两份左右参数交换的重载 int main() { // 所有断言都可正常通过,行为和普通类A完全一致 assert(C<char>{"aze"} == "xrb"); assert("xrb" == C<char>{"aze"}); assert(C<const char>{"aze"} == "xrb"); assert(C<char>{"aze"} == C<char>{"xrb"}); }
方案说明
- 该实现下
operator==不是模板函数,每个C<T>的实例都会生成一个参数为const C<T>&, const C<T>&的普通比较函数 - 调用比较运算符时,只要有一个操作数是确定的
C<T>类型,编译器就能通过ADL找到对应的比较函数,不需要再做模板参数推导 - 此时另一个操作数如果是
const T*类型,就可以正常触发构造函数做隐式转换,和普通类A的行为完全一致 - 无需额外编写左右参数交换的两份重载,也不需要任何元编程技巧,C++14环境完全支持
内容的提问来源于stack exchange,提问作者Etienne M
相关产品推荐
相关产品推荐

