雖然Concept還沒正式列入C++ Standard中,不過提早經歷過總是好事.. Concept像Interface,定義一個靜態Concept該有些什麼東西 雖然可以用Interface完成,不過有時候我們不需要Runtime Polymorphism 常見的做法是用template來做
1 2 3 4 5 6 7 8 9 10 11 12 #include <iostream> #include <string> template <typename T>void print (T obj) { std ::cout << obj.c_str() << ", length: " << obj.length() << "\n" ; } int main () { print(std ::string ("123" )); print(123 ); }
這方法最大的問題就是error message很難看懂, 常常跟Template打交道就有感覺了
1 2 3 4 5 6 7 a.cpp: In instantiation of ‘void print (T) [with T = int]’: a.cpp:23:11: required from here a.cpp:18:19: error: request for member ‘c_str’ in ‘obj’, which is of non-class type ‘int’ std::cout << obj.c_str() << ", length: " << obj.length() << "\n" ; ~~~~^~~~~ a.cpp:18:51: error: request for member ‘length’ in ‘obj’, which is of non-class type ‘int’ std::cout << obj.c_str() << ", length: " << obj.length() << "\n" ;
如果用Concept表達的話會是這個樣子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <stdio.h> #include <string> template <class T >concept bool Printable () { return requires (const T& obj) { { obj.c_str() }-> const char *; { obj.length() } -> size_t ; }; } void print (Printable obj) { printf ("%d: %s\n" , obj.length(), obj.c_str()); } int main () { print(std ::string ("123" )); print(123 ); }
1 2 3 4 5 6 7 8 9 10 11 12 13 a.cpp: In function ‘int main()’: a.cpp:17:11: error: cannot call function ‘void print (auto:1) [with auto:1 = int]’ print (123); ^ a.cpp:10:6: note: constraints not satisfied void print (Printable obj) ^~~~~ a.cpp:4:14: note: within ‘template<class T> concept bool Printable() [with T = int]’ concept bool Printable () { ^~~~~~~~~ a.cpp:4:14: note: with ‘const int& obj’ a.cpp:4:14: note: the required expression ‘obj.c_str()’ would be ill-formed a.cpp:4:14: note: the required expression ‘obj.length()’ would be ill-formed
面的Error告訴我們123不如的類型是int, 而int不符合 Printable這個Concept的要求
Limitiation Concept只是Template的一層Wrapper而已,所以這樣的程式碼也是能通過的
1 2 3 4 5 6 7 8 9 10 11 12 13 emplate <class T > concept bool Printable () { return requires (const T& obj) { { obj.c_str() }-> const char *; { obj.length() } -> size_t ; }; } void print (Printable obj) { if (!obj.empty()) { std ::cout << obj.c_str() << ", length: " << obj.length() << "\n" ; } }
明明Printable中沒定義empty的觀念,不過程式還是編譯通過,這個時候只能多加留意了