views:

78

answers:

2

I am facing the following problem: I have a class V (say a vector) from which I can produce two classes: CI and I (think of const_iterator and iterator). If I have a const V then I can only produce CI (again think of iterator and const_iterator).

Essentially I would like to subsitute (const V& v) with (CI ci) and (V& v) with (I i). Moreover I would like to be able to still pass a V obj directly to functions expecting a I or a CI hence the implicit conversions from V and const V to CI and I.

The problem I am facing is that while overloaded functions can distinguish between (const V& v) and (V& v), they cannot "distinguish" between (CI ci) and (I i) when I pass a V obj.

In code:

struct V {};

struct I 
{
    I( V& v ){}
};

struct CI
{
    CI( const V& v ){} //I would like to say const only 
};

void fun( I i )
{
    double x = 1.0;
}
void fun( CI ci )
{
    double x = 2.0;
}

void fun2( V& v )
{
    double x = 1.0;
}
void fun2( const V& v )
{
    double x = 2.0;
}

Notice I could have defined conversions operator in V (is it equivalent?) instead of defining the constructors in CI and I. Now:

V v;
const V cv;

fun2( v );
fun2( cv );

fun( v ); //AMBIGUOUS!
fun( cv );

Is there a way to solve this problem WITHOUT adding any extra indirection (i.e. the fun functions cannot be modified and v MUST be passed DIRECTLY to fun but you are free to modify everything else).

Thank you in advance for any help!

A: 

What about just using typedefs?

typedef V& I;
typedef const V& CI;

Edit:

No. See comments :)

Cogwheel - Matthew Orlando
Typedefs are just aliases. They do not create separate types so the ambiguity problem is not solved, you've just short-handed it.
@stinky472 Hence the question mark. Did that really deserve the down vote?
Cogwheel - Matthew Orlando
Oh, I'm sorry, I'm new to this site and didn't think a down vote had any kind of negative impact of the commentator. I just voted it down because I knew it wouldn't help KRao and might confuse him further. If it has a negative impact on your status, I currently cannot retract the down-vote since time has passed but if you edit the post (any slight change is okay), I can retract it.
No worries. Welcome :)
Cogwheel - Matthew Orlando
+1  A: 

What you need here is explicit constructors:

struct I 
{
    explicit I( V& v ){}
};

struct CI
{
    explicit CI( const V& v ){} //I would like to say const only 
};

Too many C++ programmers overlook the explicit keyword for constructors. All unary, parameterized constructors should be explicit by default. Implicit constructors invite ambiguity problems like these as well as leading to very goofy, roundabout conversion processes that can easily lead to problematic and very inefficient code.

Now you're set, ambiguity problem solved. Without explicit constructors, you cannot prevent this ambiguity problem.

For the client code, you do need to modify it to be explicit about its conversions:

V v;
const V cv;

fun2( I(v) );
fun2( CI(cv) );

fun( I(v) );
fun( CI(cv) );

Such syntax will be required now to construct objects of I or CI, but that's a good thing: no one can accidentally introduce ambiguity problems anymore.