C/C++ 作为 C# 语言的前置版本,ECMA工业化编程语言,自然是存在 “泛型模板约束” 的功能的,只是本文不以 C/C++ 20 新语法搞出来的 “requires” 关键字来实现,它很难用!
CPP参考:(新标准)
模板对于类型的约束:
约束 template_get_size 泛型T只允许接受类型:list<T>,其实为 C/C++ 泛型模板例化特性,但与泛型模板例化略微有些区别,因为是带泛型类型约束条件的特例化。
template<typename T> class list { public: int count = 0; }; template<typename T> struct template_get_size; template<typename T> struct template_get_size<list<T> > { inline std::size_t size(list<T>& v) { return v.count; } }; int main(int argc, const char* argv[]) noexcept { list<int> list_; list_.count = 100; template_get_size<list<int> > list_get_size_; printf("%d\n", list_get_size_.size(list_)); return 0; }
但,template_get_size<int> 仍然可以尝试编译,从语法层面没有问题,但会编译失败,原因:C/C++ 使用不完整的类型。
人们无法在编译期间来增加更多检查约束的有效性。
例一:
template<typename T> struct template_get_size { static_assert(false, "Type constraints of generic templates are violated."); };
例二:
template<typename T> struct template_get_size; template<typename T> struct template_get_size<T> { static_assert(false, "Type constraints of generic templates are violated."); };
上述适用于泛型模板类/结构体,同理泛型模板函数仍可以增加泛型约束,只是没有办法向模板类型一样可以明确的约束T到底需要是什么类型,这取决于模板函数内部的实现,根代码粘合剂差不多,但不意味着不能精确限制那些T类型。
泛型模板类型例化:
class A {}; class B : public A {}; template<typename T> class say; template<> class say<A> {};
例如:人们需要T是一个指针,那么有以下几种方法约束:
案例一:
template<typename T> void foo(const T* v) {}
案例二:
template<typename T> void foo(const T& v) { typedef typename std::remove_pointer<T>::type element_type; element_type* p = NULL; }
如果:
人们需要T是一个基类,那么这种似乎不需要模板来实现,如果是模板大约是这样的形式:
约束T必须是A类或其派生类型,但使用该模板函数的开放人员只有两个途径搞清楚T到底被约束为什么。
即:1、函数注释上明确T的约束类型,2、查看模板函数的内部实现,不像C#中明确为泛型模板类型 T 增加显示一致性的 where T 约束条件。
class A {}; class B : public A {}; template<typename T> void foo(const T* v) { A* a = const_cast<T*>(v); } int main(int argc, const char* argv[]) noexcept { B b; foo(&b); return 0; }
一个好的建议是:
每个泛型模板的类型约束都应在类型/函数注释上明确指出,这样使用模板的开发人员不需要尝试预编译代码或阅读模板代码实现来判定模板代码约束条件。
THE END
喜欢就支持一下吧