在使用std :: map类型作为模板的C ++模板化函数中,我可以使用T :: key_type和T :: value_type来创建键和值。 如果T是Collections :: Generic :: Dictionary,那么在C ++ / CLI中是否存在等价物?
上看不到任何内容我想按照以下方式做点什么:
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;
}
答案 0 :(得分:2)
可能有更好的方法,但是:从Visual Studio 2010开始,C ++ / CLI编译器支持许多新的C ++ 1x功能,包括decltype
和auto
。使用这些,您可以执行以下操作:
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;
}
};