How to overcome overloading ambiguity

F

Fred Zwarts

In my software I need a vector of boolean values.
My first attempt was to use vector<bool>, but vector has a specialization for the bool type
with unwanted implications. For example, I need to pass elements of the vector as
reference to bool (bool&) to certain functions which may modify the value of such elements.
This is not possible with vector<bool>.

My next idea was to create a class Boolean_t which can be used instead of the bool type,
with transparent functionality. So I attempted the following:

class Boolean_t {
private:
bool Flag;

public:

// Normal constructor:

Boolean_t (const bool InitialValue = false) : Flag (InitialValue) {}

// Define conversion to bool and reference to bool.

operator bool () const {
return Flag;
}

operator bool & () {
return Flag;
}
};

My problem is with two operator definitions. I need both.
The first one is needed to convert a const object to a bool value,
which cannot be done with the second one.
The second one is needed to pass objects of type Boolean_t to functions that need a reference to bool,
which cannot be done with the first one.

However, if an object of type Boolean_t is used in a boolean expression, the compiler complains
about an ambiguity in the reference to a conversion function. Indeed, I understand that both
of these conversion functions could be used in this case.
Is there a solution to overcome this ambiguity and to keep the functionality?
 
P

Pascal J. Bourguignon

Fred Zwarts said:
In my software I need a vector of boolean values.
My first attempt was to use vector<bool>, but vector has a specialization for the bool type
with unwanted implications. For example, I need to pass elements of the vector as
reference to bool (bool&) to certain functions which may modify the value of such elements.
This is not possible with vector<bool>.

My next idea was to create a class Boolean_t which can be used instead of the bool type,
with transparent functionality. So I attempted the following:

class Boolean_t {

Just do:


#include <iostream>
#include <vector>

namespace My { typedef unsigned char Bool; enum { no=0,yes=1 }; }
int main(){
std::vector<My::Bool> v;
v.push_back(My::no);
v.push_back(My::yes);
My::Bool& b=(*(v.begin()));
b=My::yes;
std::cout<<int(v.front())<<" "<<int(v.back())<<std::endl;
return(0);
}


/*
-*- mode: compilation; default-directory: "/tmp/" -*-
Compilation started at Tue Jun 16 12:16:38

SRC="/tmp/b.c++" ; EXE="b" ; g++ -g3 -ggdb3 -o ${EXE} ${SRC} && ./${EXE} && echo status = $?
1 1
status = 0

Compilation finished at Tue Jun 16 12:16:39
*/
 
F

Fred Zwarts

Pascal J. Bourguignon said:
Just do:


#include <iostream>
#include <vector>

namespace My { typedef unsigned char Bool; enum { no=0,yes=1 }; }
int main(){
std::vector<My::Bool> v;
v.push_back(My::no);
v.push_back(My::yes);
My::Bool& b=(*(v.begin()));
b=My::yes;
std::cout<<int(v.front())<<" "<<int(v.back())<<std::endl;
return(0);
}


/*
-*- mode: compilation; default-directory: "/tmp/" -*-
Compilation started at Tue Jun 16 12:16:38

SRC="/tmp/b.c++" ; EXE="b" ; g++ -g3 -ggdb3 -o ${EXE} ${SRC} && ../${EXE} && echo status = $?
1 1
status = 0

Compilation finished at Tue Jun 16 12:16:39
*/

I don't think My::Bool is the transparent replacement for bool that I meant.
I can't assign true or false. The sizeof My::Bool may be different from the sizeof bool.
I can't use My::Bool in functions that need a reference to bool (bool&) parameter.

The Boolean_t class is much more transparent. The only remaining problem is the ambiguity
between two functionally equivalent operators. If I remove operator bool, everything works
transparently. The bool and Boolean_t types can be interchanged and mixed in expressions.
Only it does not work for const objects.

For const objects another (const) conversion function is needed, but I don't see
how that can be done without creating a ambiguity.
It would be sufficient to change somehow the precedence arbitrarily so that the compiler takes
one of the two.
 
M

Michael Doubez

In my software I need a vector of boolean values.
My first attempt was to use vector<bool>, but vector has a specialization for the bool type
with unwanted implications. For example, I need to pass elements of the vector as
reference to bool (bool&) to certain functions which may modify the value of such elements.
This is not possible with vector<bool>.

My next idea was to create a class Boolean_t which can be used instead of the bool type,
with transparent functionality. So I attempted the following:

class Boolean_t {
 private:
  bool Flag;

 public:

// Normal constructor:

  Boolean_t (const bool InitialValue = false) : Flag (InitialValue) {}

// Define conversion to bool and reference to bool.

  operator bool () const {
    return Flag;
  }

Which can be replaced by:
operator const bool& () const {return Flag; }
  operator bool & () {
    return Flag;
  }

};

My problem is with two operator definitions. I need both.
The first one is needed to convert a const object to a bool value,
which cannot be done with the second one.
The second one is needed to pass objects of type Boolean_t to functions that need a reference to bool,
which cannot be done with the first one.

However, if an object of type Boolean_t is used in a boolean expression, the compiler complains
about an ambiguity in the reference to a conversion function.

Can you post an example ?
 
F

Fred Zwarts

Michael Doubez said:
Which can be replaced by:
operator const bool& () const {return Flag; }


Can you post an example ?

I followed your suggestion, because it even allows references to const objects.
It does not make a difference for ambiguity according to the compiler.
However, I now see that another compiler does not complain.

When I then try something like:

Boolean_t Value;

.....


if (Value) {
....
}

Then one compiler complains about the expression in the if statement that there is an ambiguity
in choosing between the two operators.
Another compiler, however, does not complain.
Which one is right?
 
M

Michael Doubez

I followed your suggestion, because it even allows references to const objects.

Doesn't make a lot of difference here. const reference bind to lvalue.
It does not make a difference for ambiguity according to the compiler.
However, I now see that another compiler does not complain.

When I then try something like:

Boolean_t Value;

....

if (Value) {
...

}

Then one compiler complains about the expression in the if statement that there is an ambiguity
in choosing between the two operators.
Another compiler, however, does not complain.
Which one is right?

Which compilers ?
This seems to compile fine with MSVC9 and g++ and I don't see the
problem.
 
F

Fred Zwarts

I followed your suggestion, because it even allows references to const objects.

Doesn't make a lot of difference here. const reference bind to lvalue.
It does not make a difference for ambiguity according to the compiler.
However, I now see that another compiler does not complain.

When I then try something like:

Boolean_t Value;

....

if (Value) {
...

}

Then one compiler complains about the expression in the if statement that there is an ambiguity
in choosing between the two operators.
Another compiler, however, does not complain.
Which one is right?

Which compilers ?
This seems to compile fine with MSVC9 and g++ and I don't see the
problem.

Well, in fact the program that complains is not a compiler, but a lint program.
FlexeLint 9.0b to be exact. (See www.gimpel.com.)
If it can be explained that this is a bug in FlexeLint, I could file a bug report.
 
B

Bo Persson

Fred said:
In my software I need a vector of boolean values.
My first attempt was to use vector<bool>, but vector has a
specialization for the bool type
with unwanted implications. For example, I need to pass elements of
the vector as
reference to bool (bool&) to certain functions which may modify the
value of such elements.
This is not possible with vector<bool>.

One option is to use a std::deque<bool>, which behaves almost like a
vector in most situatíons.



Bo Persson
 
M

Michael Doubez

Doesn't make a lot of difference here. const reference bind to lvalue.






Which compilers ?
This seems to compile fine with MSVC9 and g++ and I don't see the
problem.

Well, in fact the program that complains is not a compiler, but a lint program.
FlexeLint 9.0b to be exact. (Seewww.gimpel.com.)
If it can be explained that this is a bug in FlexeLint, I could file a bug report.

It is a bug then. I guess the overload resolution is not performed.
The cv-qualifier of the non-static member function should be enough
and the tol=ols says it is not.

I note that §12.3/2 doesn't specify overload resolution should be
performed: only unambiguous and access control are required. I assume
unambiguous means name lookup and overload resolution.
 

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,756
Messages
2,569,533
Members
45,006
Latest member
LauraSkx64

Latest Threads

Top