Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

C++/CLI - How to convert List<T> to vector<T>

3,134 views
Skip to first unread message

JohnR

unread,
Sep 28, 2009, 9:33:52 AM9/28/09
to
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]

unread,
Sep 28, 2009, 12:29:32 PM9/28/09
to

"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.

Victor Bazarov

unread,
Sep 28, 2009, 1:03:51 PM9/28/09
to
Ben Voigt [C++ MVP] wrote:
>
>
> "JohnR" <_no_spam@_no_spam.com> wrote in message
> news:#1hpNBEQ...@TK2MSFTNGP04.phx.gbl...
>> 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);

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

JohnR

unread,
Sep 28, 2009, 1:26:54 PM9/28/09
to
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.

> 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.


Ben Voigt [C++ MVP]

unread,
Sep 28, 2009, 3:02:31 PM9/28/09
to
> 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.

Ben Voigt [C++ MVP]

unread,
Sep 28, 2009, 3:06:36 PM9/28/09
to
> 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.

> 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.

0 new messages