C++嵌套SFINAE模板使用自定义common_type包装类编译错误如何解决
问题原因
SFINAE(替换失败不是错误)规则仅对模板参数替换的直接上下文生效。你当前的自定义MyCommonType是非SFINAE友好的:
- 当实例化
MyCommonType<T, U>时,其内部的typedef std::common_type_t<T, U> type;语句的错误发生在MyCommonType自身的实例化上下文,不属于运算符模板的直接上下文,因此会被判定为硬错误,不会触发SFINAE排除候选。 - 直接使用
std::common_type_t时,替换错误发生在运算符模板签名的直接上下文,因此可以正常触发SFINAE。
解决方案
将MyCommonType改造为SFINAE友好的实现:增加一个默认模板参数,用std::void_t检测std::common_type<T, U>是否存在合法的type成员,仅在检测通过时才为MyCommonType定义type成员。
如果使用C++17及以上标准,修改MyCommonType的定义如下:
// 主模板:无合法common_type时不提供type成员 template<typename T, typename U, typename = void> struct MyCommonType {}; // 偏特化:仅当std::common_type<T,U>存在type成员时匹配 template<typename T, typename U> struct MyCommonType<T, U, std::void_t<std::common_type_t<T, U>>> { typedef std::common_type_t<T, U> type; }; template<typename T, typename U> using MyCommonTypeT = typename MyCommonType<T, U>::type;
如果使用C++11/14,标准库没有提供std::void_t,可以自行定义:
// C++11/14 自行实现void_t template<typename...> using void_t = void; template<typename T, typename U, typename = void> struct MyCommonType {}; template<typename T, typename U> struct MyCommonType<T, U, void_t<std::common_type_t<T, U>>> { typedef std::common_type_t<T, U> type; }; template<typename T, typename U> using MyCommonTypeT = typename MyCommonType<T, U>::type;
修改完成后,当std::common_type<T, U>不存在合法type时,MyCommonType<T, U>也没有type成员,此时MyCommonTypeT<T, U>的缺失::type错误将发生在运算符模板的直接上下文,触发SFINAE将不符合要求的重载从候选列表中排除,代码可以正常编译。
内容的提问来源于stack exchange,提问作者Jeff G
相关产品推荐
相关产品推荐

