Discussion:
C++/CLI - How to convert List<T> to vector<T>
(too old to reply)
JohnR
2009-09-28 13:33:52 UTC
Permalink
Hi there,

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)
Ben Voigt [C++ MVP]
2009-09-28 16:29:32 UTC
Permalink
Post by JohnR
Hi there,
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)
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.
Victor Bazarov
2009-09-28 17:03:51 UTC
Permalink
Post by Ben Voigt [C++ MVP]
Post by JohnR
Hi there,
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)
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
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);
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
Post by Ben Voigt [C++ MVP]
return result;
}
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.
Post by Ben Voigt [C++ MVP]
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
Ben Voigt [C++ MVP]
2009-09-28 19:02:31 UTC
Permalink
Post by Victor Bazarov
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 (...
Yes, reserve is what I intended. Sorry about that.
JohnR
2009-09-28 17:26:54 UTC
Permalink
Thanks for the feedback. I've literally just started playing with C++/CLI in
the past 24 hours. It's not entirely clear to me yet what the rules are for
mixing managed and unmanaged types, let alone templates and generics. See
comments below.
Post by Ben Voigt [C++ MVP]
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
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).
Post by Ben Voigt [C++ MVP]
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.
Ben Voigt [C++ MVP]
2009-09-28 19:06:36 UTC
Permalink
Post by JohnR
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
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.
Post by JohnR
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
Post by JohnR
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.

Continue reading on narkive:
Search results for 'C++/CLI - How to convert List<T> to vector<T>' (Questions and Answers)
10
replies
what is GIS?
started 2006-06-13 03:41:34 UTC
science & mathematics
Loading...