今天有一同学在群上聊到一个比较好玩的题目(本人看书不多,后面才知是《C++模板元编程》第二章里面的一道习题), 我也抱着试一试的态度去完成它, 这道题也体现了c++模板元编程的基础和精髓: 类型就是数据。
题目如下所述:
Write a ternary metafunction replace_type<c,x,y> that takes an arbitrary compound type c as its first parameter, and replaces all occurrences of a type x within c with y:
typedef replace_type< void*, void, int >::type t1; // int* typedef replace_type< int const*[10] , int const , long >::type t2; // long* [10] typedef replace_type< char& (*)(char&) , char& , long& >::type t3; // long& (*)(long&)
下面第一部分是我的实现, 第二部分是测试代码:
1. 实现
namespace xusd{ template <typename C, typename X, typename Y> struct replace_type; template <typename X, typename Y> struct replace_type<X, X, Y>{ typedef Y type; }; template <typename C, typename X, typename Y> struct replace_type_impl{ typedef C type; }; template <typename C, typename X, typename Y> struct replace_type:public replace_type_impl<C, X, Y>{ }; template <typename C, typename X, typename Y> struct replace_type_impl<C const, X, Y>{ typedef typename replace_type<C, X, Y>::type const type; }; template <typename C, typename X, typename Y> struct replace_type_impl<C volatile, X, Y>{ typedef typename replace_type<C, X, Y>::type volatile type; }; template <typename C, typename X, typename Y> struct replace_type_impl<C *, X, Y>{ typedef typename replace_type<C, X, Y>::type * type; }; template <typename C, typename X, typename Y> struct replace_type_impl<C &, X, Y>{ typedef typename replace_type<C, X, Y>::type & type; }; template <typename C, typename X, typename Y> struct replace_type_impl<C &&, X, Y>{ typedef typename replace_type<C, X, Y>::type && type; }; template <typename C, typename X, typename Y> struct replace_type_impl<C[], X, Y>{ typedef typename replace_type<C, X, Y>::type type[]; }; template <typename C, typename X, typename Y, unsigned N> struct replace_type_impl<C [N], X, Y>{ typedef typename replace_type<C, X, Y>::type type[N]; }; template <typename C, typename Class, typename X, typename Y> struct replace_type_impl<C Class::*, X, Y>{ typedef typename replace_type<C, X, Y>::type Class::* type; }; template <typename R, typename X, typename Y,typename... Args> struct replace_type_impl<R(Args...), X, Y>{ typedef typename replace_type<R, X, Y>::type type(typename replace_type<Args, X, Y>::type...); }; }
2. 测试
1 #include <type_traits> 2 #include <gtest/gtest.h> 3 4 #define MYTEST(Res, C, X , Y) EXPECT_TRUE((std::is_same<Res, xusd::replace_type<C, X, Y>::type >::value)) 5 6 TEST(TestReplaceType, TestSimple){ 7 EXPECT_TRUE((std::is_same<int*, xusd::replace_type<void*, void, int>::type >::value)); 8 MYTEST(int*, void*, void, int); 9 MYTEST(long*[10], int const*[10], int const, long); 10 11 MYTEST(int const *[10], int const*[10], char, long); 12 } 13 14 TEST(TestReplaceType, TestSameType){ 15 MYTEST(int const*[10], int const*[10], int const, int const); // X == Y 16 17 MYTEST(long , int const*[10], int const*[10], long); // C == X 18 } 19 20 21 TEST(TestReplaceType, TestClass){ 22 class A; 23 MYTEST(long A::* , int A::*, int, long); 24 25 MYTEST(long (A::*)(char, long) , int (A::*)(char, int), int, long); 26 } 27 TEST(TestReplaceType, TestReference){ 28 MYTEST(long&&, int&&, int, long); 29 MYTEST(long const&&, int const&&, int, long); 30 MYTEST(long&, int&, int, long); 31 MYTEST(long const&, int const&, int, long); 32 33 } 34 TEST(TestReplaceType, TestArray){ 35 MYTEST(double[], int[], int , double); 36 MYTEST(double[10], int[10], int , double); 37 } 38 //TEST(TestReplaceType, TestSimple){} 39 TEST(TestReplaceType, TestFuntion){ 40 EXPECT_TRUE((std::is_same<long&(*)(long&), xusd::replace_type<char&(*)(char&), char&, long&>::type >::value)); 41 EXPECT_TRUE((std::is_same<long&(*)(long&, long&), xusd::replace_type<char&(*)(char&, char&), char&, long&>::type >::value)); 42 EXPECT_TRUE((std::is_same<long&(*)(long&, long&, long&), xusd::replace_type<char&(*)(char&, char&, char&), char&, long&>::type >::value)); 43 EXPECT_TRUE((std::is_same<long&(*)(long&, long&, long&, long&), xusd::replace_type<char&(*)(char&, char&, char& , char&), char&, long&>::type >::value)); 44 45 EXPECT_TRUE((std::is_same<int&, xusd::replace_type<void (&)(int, long, double), void(int, long, double), int>::type >::value)); 46 EXPECT_TRUE((std::is_same<int*, xusd::replace_type<void (*)(int, long, double), void(int, long, double), int>::type >::value)); 47 48 EXPECT_TRUE((std::is_same<int(*)(char, char), xusd::replace_type<void (*)(int, long, double), void(int, long, double), int(char, char)>::type >::value)); 49 } 50 51 52 int main(int argc, char* argv[]){ 53 54 testing::InitGoogleTest(&argc, argv); 55 return RUN_ALL_TESTS(); 56 }