C++二级模板参数校验报错:是否可解决及方案建议
C++二级模板继承约束问题解决
问题重现
用户定义了如下二级模板结构:
类型定义
class Type{}; class TypeExt:public Type{};
第一层模板
// 类型必须继承自 Type template<typename T, typename std::enable_if<std::is_base_of<Type, T>::value>::type* = nullptr> class FirstLevel{}; class FirstLevelSpecialization_1:public FirstLevel<Type>{}; class FirstLevelSpecialization_2:public FirstLevel<TypeExt>{};
第二层模板
// 类型必须继承自 FirstLevel template<typename T, typename std::enable_if<std::is_base_of<FirstLevel, T>::value>::type* = nullptr> class SecondLevel{}; class SecondLevelSpecialization: public SecondLevel<FirstLevelSpecialization_1>{};
上述最后一行代码报错:Invalid template arguments。用户提出两个问题:
- 该问题在C++中是否可解决?
- 若可解决,烦请提供相关解决思路?
问题解答
可以解决。
解决思路:
问题本质:
FirstLevel是模板类,并非具体类型,std::is_base_of的第一个参数要求是具体类类型,不能是未实例化的模板。而FirstLevelSpecialization_1继承的是实例化后的FirstLevel<Type>,而非FirstLevel模板本身,因此原约束条件不成立,导致模板参数校验失败。思路一:自定义类型 trait 检测是否继承自任意实例化的
FirstLevel
利用SFINAE机制,编写通用类型判断工具,检查目标类型是否能转换为某个实例化的FirstLevel<U>:#include <type_traits> class Type{}; class TypeExt:public Type{}; template<typename T, typename std::enable_if<std::is_base_of<Type, T>::value>::type* = nullptr> class FirstLevel{}; class FirstLevelSpecialization_1:public FirstLevel<Type>{}; class FirstLevelSpecialization_2:public FirstLevel<TypeExt>{}; // 类型 trait 实现 template<typename T> auto is_derived_from_firstlevel_impl(int) -> std::true_type; template<typename T> auto is_derived_from_firstlevel_impl(...) -> std::false_type; template<typename T> struct is_derived_from_firstlevel : decltype(is_derived_from_firstlevel_impl<T>(0)) {}; // 针对FirstLevel<U>的直接特化 template<typename U> struct is_derived_from_firstlevel<FirstLevel<U>> : std::true_type {}; // 修改后的SecondLevel模板 template<typename T, typename std::enable_if<is_derived_from_firstlevel<T>::value>::type* = nullptr> class SecondLevel{}; class SecondLevelSpecialization: public SecondLevel<FirstLevelSpecialization_1>{}; // 编译通过思路二:给
FirstLevel添加非模板基类
定义一个非模板基类,让所有实例化的FirstLevel都继承该基类,直接用std::is_base_of检查这个非模板基类即可:#include <type_traits> class Type{}; class TypeExt:public Type{}; // 新增非模板基类 class FirstLevelBase {}; template<typename T, typename std::enable_if<std::is_base_of<Type, T>::value>::type* = nullptr> class FirstLevel : public FirstLevelBase {}; class FirstLevelSpecialization_1:public FirstLevel<Type>{}; class FirstLevelSpecialization_2:public FirstLevel<TypeExt>{}; // 检查是否继承自FirstLevelBase template<typename T, typename std::enable_if<std::is_base_of<FirstLevelBase, T>::value>::type* = nullptr> class SecondLevel{}; class SecondLevelSpecialization: public SecondLevel<FirstLevelSpecialization_1>{}; // 编译通过
内容的提问来源于stack exchange,提问作者Alex Luya
相关产品推荐
相关产品推荐

