Resolving ambiguity

B

beclan

Hello,

Does any of you guys how to solve the following ambiguity?

Consider the following class declaration snippet:

class Foo {
:
public:
SomeDataType& operator [](unsigned);
SomeDataType& operator [](const char*);
:
};

Now, the ambiguity occurs here:

void myBigBar()
{
Foo obj;

obj[0].method(); // <= ambiguous call!
}

Anybody has any ideas as to how to resolve this?

Thanks.
 
J

Johannes Schaub (litb)

beclan said:
Hello,

Does any of you guys how to solve the following ambiguity?

Consider the following class declaration snippet:

class Foo {
:
public:
SomeDataType& operator [](unsigned);
SomeDataType& operator [](const char*);
:
};

Now, the ambiguity occurs here:

void myBigBar()
{
Foo obj;

obj[0].method(); // <= ambiguous call!
}

Anybody has any ideas as to how to resolve this?
Yes, change `op[]` to `int`. And introduce overloads for `unsigned int`,
`long`, `unsigned long`. forward to the `unsigned long` version. Or write it
as a template

template<typename T>
typename enable_if<is_integral<T>, SomeDataType&>::type
operator [](T);

The problem is that `int` -> `unsigned` is not any better than `int` -> `P*`
for a null pointer constant. This is because of the cursed null pointer
constant rules, which nullptr in c++0x hopefully fixes. Another option is to
use `std::string const&` instead of `char const*`, and string will be worse
than unsigned because it needs a user defined conversion. Hope this helps.

If you don't have control over the class, the following should do it too

obj[0,0].method();

This makes use of those scary "tricks". Not sure whether you are ready to
abuse the language in this way.
 
B

beclan

beclan said:
Hello,

Does any of you guys how to solve the following ambiguity?

Consider the following class declaration snippet:

class Foo {
:
public:
SomeDataType& operator [](unsigned);
SomeDataType& operator [](const char*);
:
};

Now, the ambiguity occurs here:

void myBigBar()
{
Foo obj;

obj[0].method(); //<= ambiguous call!
}

Anybody has any ideas as to how to resolve this?
Yes, change `op[]` to `int`. And introduce overloads for `unsigned int`,
`long`, `unsigned long`. forward to the `unsigned long` version. Or write it
as a template

template<typename T>
typename enable_if<is_integral<T>, SomeDataType&>::type
operator [](T);

The problem is that `int` -> `unsigned` is not any better than `int` -> `P*`
for a null pointer constant. This is because of the cursed null pointer
constant rules, which nullptr in c++0x hopefully fixes. Another option is to
use `std::string const&` instead of `char const*`, and string will be worse
than unsigned because it needs a user defined conversion. Hope this helps.

If you don't have control over the class, the following should do it too

obj[0,0].method();

This makes use of those scary "tricks". Not sure whether you are ready to
abuse the language in this way.

Fantastic explanation Johannes! Will be introducing the overloads you
suggested as it seems to be the most language-compliant solution.

Much obliged for taking the time.
 
J

James Kanze

Does any of you guys how to solve the following ambiguity?
Consider the following class declaration snippet:
class Foo {
:
public:
SomeDataType& operator [](unsigned);
SomeDataType& operator [](const char*);
:

Now, the ambiguity occurs here:
void myBigBar()
{
Foo obj;
obj[0].method(); // <= ambiguous call!
}
Anybody has any ideas as to how to resolve this?

The obvious solution is to write
obj[0U].method(); // :)

But I'd recommend overloading for int as well, e.g.:
// in Foo:
SomeDataType& operator[]( int i )
{
assert( i >= 0 );
return operator[]( static_cast< unsigned >( i ) );
}

More generally, anytime a function is overloaded, and the
overloads include a numeric type, add an overload for int; if
the overloads also include a floating point type, it's probably
a good idea to ensure that there is one for float as well.

Note too that if you do this, obj[NULL] will still call the int
version (probably---an implementation could define NULL as
0UL, for example). A good implementation will warn in such
cases, but the standard says that it's legal, and that that's
what should happen.
 
M

Marco Manfredini

Johannes said:
If you don't have control over the class, the following should do it too

obj[0,0].method();

This makes use of those scary "tricks". Not sure whether you are ready to
abuse the language in this way.

in that case:
obj[0u].method();
 
J

Johannes Schaub (litb)

Marco said:
Johannes said:
If you don't have control over the class, the following should do it too

obj[0,0].method();

This makes use of those scary "tricks". Not sure whether you are ready to
abuse the language in this way.

in that case:
obj[0u].method();

Shame on me for not telling him that. I suppose i should explaim him why "0,
0" works, though. It makes it so it's not a null pointer constant anymore.
So the pointer version will never be considered. Same reason why the
following fails on a conforming compiler because the size is not a constant
expression

int a[(0, 0)];

Cheers!
 
V

Vladimir Jovic

Johannes said:
beclan said:
Hello,

Does any of you guys how to solve the following ambiguity?

Consider the following class declaration snippet:

class Foo {
:
public:
SomeDataType& operator [](unsigned);
SomeDataType& operator [](const char*);
:
};
[...]

If you don't have control over the class, the following should do it too

obj[0,0].method();

This makes use of those scary "tricks". Not sure whether you are ready to
abuse the language in this way.

Sorry to ask stupid questions, but what exactly happens when you do this:
obj[0,0].method();
?
How is 0,0 interpreted?
 
A

Anthony Williams

beclan said:
Hello,

Does any of you guys how to solve the following ambiguity?

Consider the following class declaration snippet:

class Foo {
:
public:
SomeDataType& operator [](unsigned);
SomeDataType& operator [](const char*);
:
};

Now, the ambiguity occurs here:

void myBigBar()
{
Foo obj;

obj[0].method(); // <= ambiguous call!
}

Anybody has any ideas as to how to resolve this?

0 is an integer, so it can convert to both unsigned. It is also a null
pointer constant so can convert to const char*. Hence the ambiguity.

There are 4 ways to resolve this:

1: Change the signature of operator[](unsigned) to operator[](int)

This has the downside that now you have to handle negative indices.

2: Add an overload of operator[](int) that checks for positive values
and forwards to operator[](unsigned)

3: Write obj[0u].method() to force the literal to be an unsigned integer

4: Write obj[(unsigned)0].method() to cast 0 to unsigned.

Anthony
 
V

Victor Bazarov

Vladimir said:
Johannes said:
beclan said:
Hello,

Does any of you guys how to solve the following ambiguity?

Consider the following class declaration snippet:

class Foo {
:
public:
SomeDataType& operator [](unsigned);
SomeDataType& operator [](const char*);
:
};
[...]

If you don't have control over the class, the following should do it too

obj[0,0].method();

This makes use of those scary "tricks". Not sure whether you are ready
to abuse the language in this way.

Sorry to ask stupid questions, but what exactly happens when you do this:
obj[0,0].method();
?
How is 0,0 interpreted?

It's an expression with the comma operator. Its value is the last 0.
Its type is [probably] 'int'. The idea is that it's not convertible to
the null pointer since it isn't a compile-time constant expression...

V
 
J

Johannes Schaub (litb)

Vladimir said:
Johannes said:
beclan said:
Hello,

Does any of you guys how to solve the following ambiguity?

Consider the following class declaration snippet:

class Foo {
:
public:
SomeDataType& operator [](unsigned);
SomeDataType& operator [](const char*);
:
};
[...]

If you don't have control over the class, the following should do it too

obj[0,0].method();

This makes use of those scary "tricks". Not sure whether you are ready to
abuse the language in this way.

Sorry to ask stupid questions, but what exactly happens when you do this:
obj[0,0].method();
?
How is 0,0 interpreted?
This is just so that you don't have to worry what integer overloads there
are. If you cast to unsigned, then it will call the unsigned. But the next
class may use unsigned long/size_t/ptrdiff_t as index type and you will have
to cast to a different type...

"0,0" is application of the comma operator, and its result is not a null
pointer constant. Thus, the pointer overload is not considered.
 

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

Members online

Forum statistics

Threads
473,769
Messages
2,569,577
Members
45,054
Latest member
LucyCarper

Latest Threads

Top