在C ++ / CLI中是否有类似于Collections :: Generic :: Dictionary的map :: key_type?

时间:2014-07-03 12:48:44

标签: .net templates c++-cli

在使用std :: map类型作为模板的C ++模板化函数中,我可以使用T :: key_type和T :: value_type来创建键和值。 如果T是Collections :: Generic :: Dictionary,那么在C ++ / CLI中是否存在等价物?

我在the MSDN Dictionary page

上看不到任何内容

我想按照以下方式做点什么:

   template<typename T> // T is a Collections::Generic::Dictionary
   T^ Copy(T^ src)
   {
      T^ dst;
      Threading::Monitor::Enter(src);
      try
      {
         dst = gcnew T(src);
         for each (T::key_type^ key in src->Keys) // no such type!
         {
            T::value_type^ srcValue = dynamic_cast<T::value_type^>(src[key]); // no such type!
            if (srcValue)
            {
               T::value_type^ copiedValue = gcnew T::value_type(/*some values common to my value types here*/); // no such type!
               copiedValue->Clone(*srcValue);
               dst->Add(key, copiedValue);
            }
         }
      }
      finally
      {
         Threading::Monitor::Exit(src);
      }
      return dst;
   }

2 个答案:

答案 0 :(得分:2)

可能有更好的方法,但是:从Visual Studio 2010开始,C ++ / CLI编译器支持许多新的C ++ 1x功能,包括decltypeauto。使用这些,您可以执行以下操作:

typedef decltype(src->Keys->GetEnumerator().Current) key_type;
typedef decltype(src->Values->GetEnumerator().Current) value_type;

或者

auto srcValue = src[key];

对于旧版本,您可以尝试部分模板专业化:

#include "stdafx.h"

using namespace System;

ref class Val
{
public:
    void CloneFrom(Val^) {}
};

template<typename D> struct dictionary_traits;
template<typename K, typename V> struct dictionary_traits<Collections::Generic::Dictionary<K, V>>
{
    typedef K key_type;
    typedef V value_type;
};

template<typename T> struct strip_managed;
template<typename T> struct strip_managed<T^>
{
    typedef T type;
};

template<typename T> // T is a Collections::Generic::Dictionary
T^ Copy(T^ src)
{
    typedef typename dictionary_traits<T>::key_type key_type;
    typedef typename dictionary_traits<T>::value_type value_type;

    T^ dst;
    Threading::Monitor::Enter(src);
    try
    {
        dst = gcnew T(src);
        for each (key_type key in src->Keys)
        {
            value_type srcValue = src[key];
            if (srcValue)
            {
                value_type copiedValue = gcnew typename strip_managed<value_type>::type();
                copiedValue->CloneFrom(srcValue);
                dst->Add(key, copiedValue);
            }
        }
    }
    finally
    {
        Threading::Monitor::Exit(src);
    }
    return dst;
}

int main(array<System::String ^> ^args)
{
    auto dict = gcnew Collections::Generic::Dictionary<Object^, Val^>();
    Copy(dict);
    return 0;
}

答案 1 :(得分:2)

Dictionary是一个泛型类,而不是模板。在罗马时,就像罗马人一样,写一个通用的方法:

ref class Example {
public:
    generic<typename K, typename V>
    Dictionary<K, V>^ Copy(IDictionary<K, V>^ src) {
        auto cpy = gcnew Dictionary <K, V> ;
        for each (K key in src->Keys) cpy->Add(key, src[key]);
        return cpy;
    }
};

请注意,这会在字典中创建值的浅表副本。如果V是值类型,那么这很好,如果它是引用类型,则可能不那么好。由于垃圾收集器,它在.NET中不太需要很多。如果需要,请记住,没有通用的方法来深度复制引用类型的对象,除非您自己明确地实现它。例如,这需要一个由V类型实现的IDeepClone接口。例如:

generic<typename T>
interface class IDeepClone {
    T Copy();
};

使用 where 关键字:

通过约束告诉编译器
ref class Example {
public:
    generic<typename K, typename V> 
    where V:IDeepClone<V>
    Dictionary<K, V>^ Copy(IDictionary<K, V>^ src) {
        auto cpy = gcnew Dictionary <K, V> ;
        for each (K key in src->Keys) cpy->Add(key, src[key]->Copy());
        return cpy;
    }
};