Question

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!

Was it helpful?

Solution

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.

OTHER TIPS

What about just using typedefs?

typedef V& I;
typedef const V& CI;

Edit:

No. See comments :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top