I'm new to C++/CLI but very experierced in both C++ and .NET. Can someone
show me the basic syntax for converting a List<T> to vector<T> (or more
generally, any .NET generic to its C++ template equivalent). For now I'm
looking for a template with a signature similar to the following (note
however that "T" would also need to be converted presumably so a template
arg and a generic arg may be required). Thanks in advance.
std::vector<T> marshal_as(System::Collections::Generic::List<T> ^ const &
list)
"JohnR" <_no_spam@_no_spam.com> wrote in message
news:#1hpNBEQ...@TK2MSFTNGP04.phx.gbl...
Returning vector by value is going to have really bad performance unless you
have the move optimization.
For types which have dual managed/native identity (i.e. built-in numeric
types), something like:
template<typename T>
std::vector<T> marshal_as(System::Collections::Generic::ICollection<T>^
list)
{
if (list == nullptr) throw gcnew ArgumentNullException(L"list");
std::vector<T> result(list->Count);
for each (T& elem in list)
result.push_back(elem);
return result;
}
More generally, something like:
template<typename T>
generic<typename S>
std::vector<T> marshal_as(System::Collections::Generic::ICollection<S>^
list)
{
if (list == nullptr) throw gcnew ArgumentNullException(L"list");
std::vector<T> result(list->Count);
for each (S& elem in list)
result.push_back(marshal_as<T>(elem));
return result;
}
Not compile-tested.
That's A BAD IDEA(tm). You're going to end up with the vector that has
its first list->Count elements default-initialized and the actual
meaningful elements that follow (and total of list->Count*2 elements).
Perhaps you meant
std::vector<T> result;
result.reserve(list->Count);
for each (...
Or maybe you meant
std::vector<T> result(list->Count);
for (int i = 0; ...
result[i] = list->??? ; // or use iterators
> return result;
> }
>
> More generally, something like:
>
> template<typename T>
> generic<typename S>
> std::vector<T> marshal_as(System::Collections::Generic::ICollection<S>^
> list)
> {
> if (list == nullptr) throw gcnew ArgumentNullException(L"list");
> std::vector<T> result(list->Count);
> for each (S& elem in list)
> result.push_back(marshal_as<T>(elem));
Same notes as above.
> return result;
> }
>
> Not compile-tested.
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
> Returning vector by value is going to have really bad performance unless
> you have the move optimization.
> For types which have dual managed/native identity (i.e. built-in numeric
> types), something like:
>
> template<typename T>
> std::vector<T> marshal_as(System::Collections::Generic::ICollection<T>^
> list)
> {
> if (list == nullptr) throw gcnew ArgumentNullException(L"list");
> std::vector<T> result(list->Count);
> for each (T& elem in list)
> result.push_back(elem);
> return result;
> }
This works (thanks) but can you freely mix managed and unmanaged types. If
"T" is a "long" for instance, it's 64 bits managed and 32 bits unmanaged (on
a 32 bit system in the latter case). So what are the rules for mixing them
like this (or rather, what does "T" mean in the case of "ICollection<long>"
for instance). Note that even for types that are the same ("int" for
instance, at least on a 32-bit platform), can you freely mix the managed and
unmanaged version (isn't it like mixing apples and oranges, even they map to
the same thing).
> More generally, something like:
>
> template<typename T>
> generic<typename S>
> std::vector<T> marshal_as(System::Collections::Generic::ICollection<S>^
> list)
> {
> if (list == nullptr) throw gcnew ArgumentNullException(L"list");
> std::vector<T> result(list->Count);
> for each (S& elem in list)
> result.push_back(marshal_as<T>(elem));
> return result;
> }
This is what I was really after. I'm getting an internal compiler error
however, first I've seen since VC6 (used to get them all the time). I'll
have to play with it to see if it's possible to correct but at least I can
see the basic syntax. Thanks for your help.
Yes, reserve is what I intended. Sorry about that.
No it isn't. In C++ and C++/CLI, long is 32 bits. long long is 64 bits.
In C#, long is 64 bits.
There is no System.Long.
"long" (and related keywords) are *language-dependent* aliases for the
System.[U]Int(16|32|64) types.
> like this (or rather, what does "T" mean in the case of
> "ICollection<long>" for instance). Note that even for types that are the
> same ("int" for
System.Collections.Generic.ICollection<System.Int32> of course
> instance, at least on a 32-bit platform), can you freely mix the managed
> and unmanaged version (isn't it like mixing apples and oranges, even they
> map to the same thing).
Yes. native int and System.Int32 are considered the SAME type in C++/CLI.
There's not a mapping from one to the other, they are BOTH managed and
native. This duality is unique to the built-in types, there is no way to
make a user-defined value type that works the same way.