Indexer on generic argument

  • Thread starter christian2.schmidt
  • Start date
C

christian2.schmidt

Hi,
why does the first Console::Write give error "indexer needs array or
pointer" and the second not?

generic <typename TList, typename ItemType> where TList :
IList<ItemType>
ref class MyClass
{
public:
MyClass() {}
void Method(TList list1)
{
Console::Write("{0}, ", list1[0]); // error C2109 ??
IList<ItemType>^ list2 = list1;
Console::Write("{0}, ", list2[0]); // ok
}
};

Cheers,
Christian
 
P

Pavel Minaev

why does the first Console::Write give error "indexer needs array or
pointer" and the second not?

generic <typename TList, typename ItemType> where TList :
IList<ItemType>
ref class MyClass
{
public:
        MyClass() {}
        void Method(TList list1)
        {
                Console::Write("{0}, ", list1[0]); // error C2109 ??
                IList<ItemType>^ list2 = list1;
                Console::Write("{0}, ", list2[0]); // ok
        }

};

I can't figure out why it should be any different, but specifying the
indexer property explicitly works:

Console::Write("{0}, ", list1->default[0]);

Since there's no real reason why it shouldn't be able to figure out
the default property when the short form is used (after all, it can do
it for types which are not generic type parameters just fine!), it's
probably worth opening a suggestion on VS Connect regarding this.
 
B

Ben Voigt [C++ MVP]

Pavel said:
why does the first Console::Write give error "indexer needs array or
pointer" and the second not?

generic <typename TList, typename ItemType> where TList :
IList<ItemType>
ref class MyClass
{
public:
MyClass() {}
void Method(TList list1)
{
Console::Write("{0}, ", list1[0]); // error C2109 ??
IList<ItemType>^ list2 = list1;

This line shouldn't have worked -- list1 has stack semantics (tracking
reference), list2 is a tracking handle. You need an address-of operator to
make a handle from a reference.

Maybe changing the formal parameter to a handle "TList^ list1" would resolve
your problem?
Console::Write("{0}, ", list2[0]); // ok
}

};

I can't figure out why it should be any different, but specifying the
indexer property explicitly works:

Console::Write("{0}, ", list1->default[0]);

Since there's no real reason why it shouldn't be able to figure out
the default property when the short form is used (after all, it can do
it for types which are not generic type parameters just fine!), it's
probably worth opening a suggestion on VS Connect regarding this.
 
C

christian2.schmidt

Pavel said:
why does the first Console::Write give error "indexer needs array or
pointer" and the second not?
generic <typename TList, typename ItemType> where TList :
IList<ItemType>
ref class MyClass
{
public:
MyClass() {}
void Method(TList list1)
{
Console::Write("{0}, ", list1[0]); // error C2109 ??
IList<ItemType>^ list2 = list1;

This line shouldn't have worked -- list1 has stack semantics (tracking
reference), list2 is a tracking handle. You need an address-of operator to
make a handle from a reference.

Isn't this some kind of autocasting magic?
Maybe changing the formal parameter to a handle "TList^ list1" would resolve
your problem?

No, this gives error C3229: dereferencing a generic type parameter is
not allowed.

Thanks,
Christian
 
B

Ben Voigt [C++ MVP]

Pavel said:
On Aug 5, 9:22 pm, (e-mail address removed) wrote:
why does the first Console::Write give error "indexer needs array
or pointer" and the second not?
generic <typename TList, typename ItemType> where TList :
IList<ItemType>
ref class MyClass
{
public:
MyClass() {}
void Method(TList list1)
{
Console::Write("{0}, ", list1[0]); // error C2109 ??
IList<ItemType>^ list2 = list1;

This line shouldn't have worked -- list1 has stack semantics
(tracking reference), list2 is a tracking handle. You need an
address-of operator to make a handle from a reference.

Isn't this some kind of autocasting magic?
Maybe changing the formal parameter to a handle "TList^ list1" would
resolve your problem?

No, this gives error C3229: dereferencing a generic type parameter is
not allowed.
 
P

Pavel Minaev

generic <typename TList, typename ItemType> where TList :
IList<ItemType>
ref class MyClass
{
public:
MyClass() {}
void Method(TList list1)
{
Console::Write("{0}, ", list1[0]); // error C2109 ??
IList<ItemType>^ list2 = list1;

This line shouldn't have worked -- list1 has stack semantics (tracking
reference), list2 is a tracking handle.  You need an address-of operator to
make a handle from a reference.

It works because it's a generic declaration, not a template
declaration. Generic type parameters can only be instantiated with
handles for ref types - so, for a specific instantiation, TList would
be something like List<T>^, and not just plain List<T>.
 
B

Ben Voigt [C++ MVP]

Pavel said:
generic <typename TList, typename ItemType> where TList :
IList<ItemType>
ref class MyClass
{
public:
MyClass() {}
void Method(TList list1)
{
Console::Write("{0}, ", list1[0]); // error C2109 ??
IList<ItemType>^ list2 = list1;

This line shouldn't have worked -- list1 has stack semantics
(tracking reference), list2 is a tracking handle. You need an
address-of operator to make a handle from a reference.

It works because it's a generic declaration, not a template
declaration. Generic type parameters can only be instantiated with
handles for ref types - so, for a specific instantiation, TList would
be something like List<T>^, and not just plain List<T>.

Hmmm. Then the constraint line makes little sense. A tracking handle
doesn't implement an interface, the type of the referenced object does. I
realize this is connected to the .NET behavior of following different rules
when instantiating generics using ref types vs value types, and there
probably is no perfectly consistent syntax which expresses the behavior.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top