将N层集合对象自动转化为对应的.NET泛型对象(C++)

来源:互联网 发布:mac media player加速 编辑:程序博客网 时间:2024/05/21 11:37

昨天别人碰到的问题,晚上回来想了一下给出了一个用模板进行类型推导的解决方案。

问题本身需求很清楚,就是需要写一个Util函数,将C++里面的那些模板(template)集合对象自动转换成.NET里面的泛型(Generic)集合对象,比如将vector<int>转化成List<int>^。因为类型(Type)不定,所以用模板来进行转化是不二的选择。问题的难点在于这些集合类还可以是嵌套类型,也就是说集合里面装的还是集合(比如将vector<vector<int> >转化成List<List<int>^>^),甚至还得考虑多层集合嵌套的情况。

  1. // NativeToManagedTypeApp.cpp : main project file.
  2. // author: Anders Deng
  3. // date: 2008/8/29
  4. #include "stdafx.h"
  5. #include <vector>
  6. using namespace System;
  7. using namespace System::Collections::Generic;
  8. using namespace std;
  9. // for method overload 
  10. struct __true__value {};
  11. struct __false__value{};
  12. // some classes for type traits
  13. template<class T>
  14. struct collection_Type_Traits
  15. {
  16.     typedef __false__value isCollection;
  17.     typedef T __template__param__type;
  18. };
  19. template<typename T>
  20. struct collection_Type_Traits<std::vector<T> >
  21. {
  22.     typedef __true__value isCollection;
  23.     typedef T __template__param__type;
  24. };
  25. template<class T>
  26. struct collection_Type_Traits<List<T>^ >
  27. {
  28.     typedef __true__value isCollection;
  29.     typedef T __template__param__type;
  30. };
  31. // add more specialization template definition
  32. // ... 
  33. template<class T>
  34. struct managed_Type_Traits
  35. {
  36.     typedef __false__value isValueType;
  37.     typedef T param_type_name;
  38. };
  39. template<class T>
  40. struct managed_Type_Traits<T^>
  41. {
  42.     typedef __false__value isValueType;
  43.     typedef T param_type_name; // remove ^ from reference type
  44. };
  45. template<>
  46. struct managed_Type_Traits<int>
  47. {
  48.     typedef __true__value isValueType;
  49.     typedef int param_type_name;
  50. };
  51. // add more specialization template definition for other required value class
  52. // ...
  53. public ref class Util
  54. {
  55. public:
  56.     template<class NativeType, class ManagedType>
  57.     static ManagedType nativeToManaged(NativeType nativeObj)
  58.     {
  59.         return __nativeToManaged<NativeType, ManagedType>(nativeObj, collection_Type_Traits<NativeType>::isCollection(), managed_Type_Traits<ManagedType>::isValueType());
  60.     }
  61. private:
  62.     // collection && reference type
  63.     template<class NativeType, class ManagedType>
  64.     static ManagedType __nativeToManaged(NativeType nativeObj, __true__value, __false__value)
  65.     {
  66.         ManagedType list = gcnew managed_Type_Traits<ManagedType>::param_type_name();
  67.         for (NativeType::iterator it = nativeObj.begin(); it != nativeObj.end(); ++it)
  68.         {
  69.             typedef collection_Type_Traits<NativeType>::__template__param__type InternalNativeType;
  70.             typedef collection_Type_Traits<ManagedType>::__template__param__type InternalManagedType;
  71.             list->Add(__nativeToManaged<InternalNativeType, InternalManagedType>(*it, collection_Type_Traits<InternalNativeType>::isCollection(), managed_Type_Traits<InternalManagedType>::isValueType()));
  72.         }
  73.         return list;
  74.     }
  75.     // non-collection && reference type
  76.     template<class NativeType, class ManagedType>
  77.     static ManagedType __nativeToManaged(NativeType nativeObj, __false__value, __false__value)
  78.     {
  79.         return gcnew managed_Type_Traits<ManagedType>::param_type_name(nativeObj.c_str());
  80.     }
  81.     // non-collection && reference type
  82.     template<class NativeType, class ManagedType>
  83.     static ManagedType __nativeToManaged(NativeType nativeObj, __false__value, __true__value)
  84.     {
  85.         return nativeObj;
  86.     }
  87. };
  88. int main(array<System::String ^> ^args)
  89. {
  90.     // ----------------------------------
  91.     // test vector<int> => List<int>^
  92.     // ----------------------------------
  93.     vector<int> intV;
  94.     intV.push_back(4);
  95.     intV.push_back(5);
  96.     List<int>^ l = Util::nativeToManaged<vector<int>, List<int>^>(intV);
  97.     for each(int i in l)
  98.     {
  99.         Console::Write("{0} ", i);
  100.     }
  101.     Console::WriteLine();
  102.     // ----------------------------------
  103.     // test vector<vector<int>> => List<List<int>^>^
  104.     // ----------------------------------
  105.     vector<vector<int>> iVV;
  106.     vector<int> iV;
  107.     iV.push_back(1);
  108.     iV.push_back(2);
  109.     iVV.push_back(iV);
  110.     List<List<int>^ >^ list = Util::nativeToManaged<vector<vector<int> >, List<List<int>^>^ >(iVV);
  111.     for each(List<int>^ l in list)
  112.     {
  113.         for each(int i in l)
  114.             Console::Write("{0} ", i);
  115.         Console::WriteLine();
  116.     }
  117.     // ---------------------------------
  118.     // test vector<vector<string>> => List<List<String^>^>^
  119.     // ---------------------------------
  120.     vector<string> sV;
  121.     vector<vector<string>> sVV;
  122.     sV.push_back("abc");
  123.     sV.push_back("def");
  124.     sV.push_back("ghi");
  125.     sVV.push_back(sV);
  126.     List<List<String^>^>^ sll = Util::nativeToManaged<vector<vector<std::string>>, List<List<String^>^>^>(sVV);
  127.     for each(List<String^>^ sl in sll)
  128.     {
  129.         for each(String^ s in sl)
  130.             Console::Write("{0} ", s);
  131.         Console::WriteLine();
  132.     }
  133.     return 0;
  134. }

代码如上,就不多解释了。关于type traits可以参考这篇文章,关于特化(specialization)、偏特化(partial specialization)的文章可以看侯捷先生的《STL源码分析》。需要特别指出的是,虽然.NET的Generic原理上不支持特化和偏特化的用法(因为.NET泛型是运行时机制,考虑到.NET极强的meta data,个人觉得确实也不必要),但是C++/CLI使用的时候仍然可以利用模板来进行特化/偏特化处理。比如上面代码中的managed_Type_Traits<T^>类型就是用来提取不带^符号的原始类型,这样就可以让模板自动产生出gcnew T(...)这样的代码了。Anyway,C++的模板就跟宏(Macro)一样,就看你怎么运用其产生需要的代码了。

记得n年前学C++的时候看过不少讲模板特化,偏特化的资料,读STL、boost等Library源代码的时候也发现里面将模板元编程(TMP)的思想发挥的淋漓尽致。不过惭愧的是自己真正coding的时候还没直接用过,这次算是亲自试了一把,功能还是很强大的(当然请不要拿来与诸如Ruby这样的动态语言比,毕竟they are totally different)。

 

小结:玩TMP实际上就是与编译器斗,其乐无穷:)

 

原创粉丝点击