C ++ неявные преобразования и неоднозначность в вызове перегруженной функции - PullRequest
4 голосов
/ 24 июня 2010

Я столкнулся со следующей проблемой: у меня есть класс V (скажем, вектор), из которого я могу создать два класса: CI и I (подумайте о const_iterator и iterator). Если у меня есть const V, тогда я могу производить только CI (снова подумайте об итераторах и const_iterator).

По сути, я хотел бы заменить (const V & v) на (CI ci) и (V & v) на (I i). Более того, я хотел бы иметь возможность передавать V obj напрямую функциям, ожидающим I или CI, следовательно, неявные преобразования из V и const V в CI и I.

Проблема, с которой я сталкиваюсь, состоит в том, что, хотя перегруженные функции могут различать (const V & v) и (V & v), они не могут "различать" между (CI ci) и (I i), когда я передаю V obj.

В коде:

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;
}

Обратите внимание, что я мог бы определить оператор преобразования в V (это эквивалентно?) Вместо определения конструкторов в CI и I. Теперь:

V v;
const V cv;

fun2( v );
fun2( cv );

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

Есть ли способ решить эту проблему, БЕЗ добавления каких-либо дополнительных косвенных указаний (то есть, забавные функции не могут быть изменены, и v ДОЛЖНО быть передано ПРЯМО в забаву, но вы можете изменять все остальное).

Заранее благодарю за любую помощь!

Ответы [ 2 ]

4 голосов
/ 25 июня 2010

Здесь вам нужны явные конструкторы:

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

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

Слишком много программистов на C ++ игнорируют явное ключевое слово для конструкторов. Все унарные параметризованные конструкторы должны быть явными по умолчанию. Неявные конструкторы вызывают проблемы неоднозначности, подобные этим, а также приводят к очень глупым, обходным процессам преобразования, которые могут легко привести к проблемному и очень неэффективному коду.

Теперь все готово, проблема неоднозначности решена. Без явных конструкторов вы не сможете предотвратить эту проблему неоднозначности.

Для клиентского кода вам нужно изменить его, чтобы явно указать его преобразования:

V v;
const V cv;

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

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

Такой синтаксис теперь потребуется для создания объектов I или CI, но это хорошо: никто больше не может случайно создать проблемы неоднозначности.

0 голосов
/ 24 июня 2010

Как насчет использования typedef s?

typedef V& I;
typedef const V& CI;

Edit:

Нет. Смотрите комментарии:)

...