[VC++ 6.0] Ambiguous call to overloaded function

R

rolandz

Hi,

Maybe somebody has been fighting with the problem that I do, currently.
I have a class that has method f(). The two versions of the f() method
accept different objects: Int and Short. These objects have
constructors that allow implicit conversions from simple types. All
this has been defined as follows:

<code>
class Int
{
public:
Int(const int);
};

class Short
{
public:
Short(const short);
};

class AClass
{
public:
void f(const Int &);
void f(const Short &);
};
</code>

Further, in the code, I have a following invocation:

<code>

AClass().f( 1 ); // <--- It is important that the type is int here!

</code>

But the compiler (VC++ 6.0) says:
error C2668: 'f' : ambiguous call to overloaded function

My question is why? Do I understand C++ implicit type conversion
imcorrectly or M$ makes sbth wrong?

TIA
 
A

Alf P. Steinbach

* rolandz:
Hi,

Maybe somebody has been fighting with the problem that I do, currently.
I have a class that has method f(). The two versions of the f() method
accept different objects: Int and Short. These objects have
constructors that allow implicit conversions from simple types. All
this has been defined as follows:

<code>
class Int
{
public:
Int(const int);
};

class Short
{
public:
Short(const short);
};

class AClass
{
public:
void f(const Int &);
void f(const Short &);
};
</code>

Further, in the code, I have a following invocation:

<code>

AClass().f( 1 ); // <--- It is important that the type is int here!

</code>

But the compiler (VC++ 6.0) says:
error C2668: 'f' : ambiguous call to overloaded function

My question is why?

Either choice of function to call involves one user-defined conversion.

Do I understand C++ implicit type conversion
imcorrectly
Probably.


or M$ makes sbth wrong?

Probably... ;-) But not here.

You can write

AClass.f( Int( 1 ) );

to disambiguate.
 
R

rolandz

Alf P. Steinbach napisal(a):
You can write
AClass.f( Int( 1 ) );

This is exactly what I do not want to do... I want it to be transparent
for a user. The purpose is to provide a way to collect parameters in
some internal array of pointers in the AClass. But the parameters MUST
be allocated on stack (not heap) for performance reason.

The Int and Short classes are ment to be such wrappers on simple types
that are being allocated on stack. The conversion was designed for
transparent conversion so user even does not neet to know it.
 
A

Alf P. Steinbach

* rolandz:
Alf P. Steinbach napisal(a):



This is exactly what I do not want to do... I want it to be transparent
for a user. The purpose is to provide a way to collect parameters in
some internal array of pointers in the AClass. But the parameters MUST
be allocated on stack (not heap) for performance reason.

The Int and Short classes are ment to be such wrappers on simple types
that are being allocated on stack. The conversion was designed for
transparent conversion so user even does not neet to know it.

That doesn't make much sense.

Most probably you have a case of Premature Optimization, where every
which way you're turning the language rules seem to try to stop you
(because they're designed for meaningful code).

Perhaps post a small program that compiles and illustrates what you're
trying to do.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.

Q: What is the most annoying thing on usenet and in e-mail?
 
R

rolandz

Alf P. Steinbach napisal(a):
That doesn't make much sense.

Most probably you have a case of Premature Optimization, where every
which way you're turning the language rules seem to try to stop you
(because they're designed for meaningful code).

Perhaps post a small program that compiles and illustrates what you're
trying to do.

There are plenty of files, classes and interfaces. Following are the
most close to the problem, I think:

<code file="Operators.h">
Core::ILogMessage & operator << (Core::ILogMessage & msg,
const Impl::Serialization::ValueType::Byte & value);


Core::ILogMessage & operator << (Core::ILogMessage & msg,
const Impl::Serialization::ValueType::Int16 & value);


Core::ILogMessage & operator << (Core::ILogMessage & msg,
const Impl::Serialization::ValueType::Int32 & value);


Core::ILogMessage & operator << (Core::ILogMessage & msg,
const Impl::Serialization::ValueType::String & value);


Core::ILogMessage & operator << (Core::ILogMessage & msg,
const Impl::Serialization::ValueType::UInt16 & value);


Core::ILogMessage & operator << (Core::ILogMessage & msg,
const Impl::Serialization::ValueType::UInt32 & value);
</code>

There are more operators for more types - I've removed them from an
example...

<code file="Operators.cpp">
Core::ILogMessage & operator << (Core::ILogMessage & msg,
const Impl::Serialization::ValueType::Int16 & value)
{
msg.add(value);
return msg;
}


Core::ILogMessage & operator << (Core::ILogMessage & msg,
const Impl::Serialization::ValueType::Int32 & value)
{
msg.add(value);
return msg;
}
</code>

<code file="ILogMessage.h">
namespace Core
{
class ILogMessage : virtual public Core::Serialization::ISerializable
{
public:
virtual void add(const Core::Serialization::ISerializable & obj) = 0;

};
}
</code>

<code file="Int16.h">
namespace Impl
{
namespace Serialization
{
namespace ValueType
{
class Int16 : public Core::Serialization::ISerializable
{
short value;

public:
Int16(const short _value);

// Serializes object's data into a given stream
void serialize(Core::Serialization::IWriteStream *stream) const;

// Deserializes all object's data from a given stream
void deserialize(Core::Serialization::IReadStream *stream);
};
}
}
}
</code>

<code file="Int32.h>
namespace Impl
{
namespace Serialization
{
namespace ValueType
{
class Int32 : public Core::Serialization::ISerializable
{
long value;

public:
Int32(int _value);

// Serializes object's data into a given stream
void serialize(Core::Serialization::IWriteStream *stream) const;

// Deserializes all object's data from a given stream
void deserialize(Core::Serialization::IReadStream *stream);
};
}
}
}
</code>

There are also other types being defined identically as follows:

Byte - unsigned char
String - char *
UInt16 - unsigned short
UInt32 - unsigned long

Then I have a main file with following code:
<code file="Main.cpp">
Core::ILog * log = Impl::LogManager::get()->getLog("main");
for(unsigned long i = 0; i < 10000; ++i)
{
log->addLogEntry(Impl::Critical, &(Impl::Msg::ErrorMsg("Error %i, %s")
<< i )); // <=== There MUST be conversion.
}
</code>

Let me clarify the add() method in the ILogMessage interface
implementation that exists in the project. It stores passed parametes
as a pointer in the internal array of ISerializable pointers. Because
there is a constraint in the ILog interface implementation that stops
processing if the logging level is insufficient at the moment. Thus I
don't want to make any other activity than just temporarily store
passed arguments. They will be used if necessary.

Why on the stack? Because addLogEntry() method is to be invoked
extreamly often and operator new() introduces too much cost for
managing the arguments as well as it wuld introduce high heap
fragmentation.

If this description is insufficient for you I can prepare some small
demo project but it might cost some effort I want to avoid :|

Thanks for your attention :)
 
J

Jim Langston

rolandz said:
Hi,

Maybe somebody has been fighting with the problem that I do, currently.
I have a class that has method f(). The two versions of the f() method
accept different objects: Int and Short. These objects have
constructors that allow implicit conversions from simple types. All
this has been defined as follows:

<code>
class Int
{
public:
Int(const int);
};

class Short
{
public:
Short(const short);
};

class AClass
{
public:
void f(const Int &);
void f(const Short &);
};
</code>

Further, in the code, I have a following invocation:

<code>

AClass().f( 1 ); // <--- It is important that the type is int here!

</code>

But the compiler (VC++ 6.0) says:
error C2668: 'f' : ambiguous call to overloaded function

My question is why? Do I understand C++ implicit type conversion
imcorrectly or M$ makes sbth wrong?

TIA

Your problem is that the compiler can not determine what you mean by "1".
Is that an integer or a short? With floating point it's easier, it defaults
to double unless you add f at the end. I'm not even sure if it would have
trouble trying to determine if it wasn't a char value or not (I may test to
find out).

Your function should work for *non constants* because then it knows the type
it's declared as.

How to solve this? Well, this is a good reason for the rule "no magic
numbers". I don't know if there is a solution you would be happy with using
constants.
 

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

No members online now.

Forum statistics

Threads
473,961
Messages
2,570,131
Members
46,689
Latest member
liammiller

Latest Threads

Top