Indexer on generic argument

  • Thread starter Thread starter christian2.schmidt
  • Start date 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
 
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.
 
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.
 
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
 
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.
 
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>.
 
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.
 
Back
Top