From: JohnR on
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)


From: Ben Voigt [C++ MVP] on


"JohnR" <_no_spam@_no_spam.com> wrote in message
news:#1hpNBEQKHA.1268(a)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);
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.

From: Victor Bazarov on
Ben Voigt [C++ MVP] wrote:
>
>
> "JohnR" <_no_spam@_no_spam.com> wrote in message
> news:#1hpNBEQKHA.1268(a)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
From: JohnR on
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.


From: Ben Voigt [C++ MVP] on
> 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.