Как устранить неоднозначность вызова перегруженной функции с литералом 0 и указателем - PullRequest
10 голосов
/ 06 января 2011

Я почти уверен, что это, должно быть, уже было здесь, но я не нашел много информации о том, как решить эту проблему (без использования вызова):

Учитывая две перегрузки, я хочу, чтобы вызов с функцией с литералом 0 всегда вызывал версию unsigned int:

void func( unsigned int ) {
    cout << "unsigned int" << endl;
}

void func( void * ) {
    cout << "void *" << endl;
}

func( 0 ); // error: ambiguous call

Я понимаю, почему это происходит, но я не хочу писать func (0u) или даже func (static_cast (0)) все время. Итак, мои вопросы:

1) Есть ли рекомендуемый способ сделать это вообще?

2) Есть ли проблемы с выполнением этого следующим образом и по какой причине это работает?

void func( unsigned int ) {
    cout << "unsigned int" << endl;
}

template <typename T>
void func( T * ) {
    static_assert( std::is_same<T, void>::value, "only void pointers allowed" );
    cout << "void *" << endl;
}

func( 0 ); // calls func( unsigned int )!

Ответы [ 4 ]

3 голосов
/ 06 января 2011

То, что вы делаете в 2), работает и, вероятно, является лучшим способом сделать это.

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

func((void *) 0);
func((unsigned int) 0);
3 голосов
/ 06 января 2011

Я предлагаю вам взглянуть на нулевой указатель из C ++ 0x (см. this ).Он определяет класс, представляющий нулевые указатели любого типа.Пример, который вы только что привели, на самом деле мотивировал включение nullptr_t (класс) / nullptr (значение) в C ++ 0x.На самом деле он позволяет устранить неоднозначность этого вызова, поставив 0, если требуется версия unsigned int , и nullptr , если вам нужна другая.

Вы можете просто реализовать этот трюк в небольшом служебном классе, пока ваш компилятор не поддержит его (или просто использовать, если ваш компилятор реализует эту часть следующего стандарта).

2 голосов
/ 06 января 2011

1) Есть ли рекомендуемый способ сделать это вообще?

Проблема в том, что литерал 0 является int, а не unsigned int, и существуют допустимые преобразования из int в unsigned int и из int в void*. Я не могу сказать, что есть рекомендуемый способ решения проблемы. Помимо уже найденных способов, вы можете добавить еще одну перегрузку:

void func(int i) 
{
    assert(i >= 0);
    return func(static_cast<unsigned int>(i));
}

2) Есть ли проблемы с выполнением этого следующим образом и по какой причине это работает?

Трюк с шаблоном работает, потому что правила для разрешения вызовов функций, которые перегружены и имеют шаблонные версии, предназначены для предпочтения не шаблонных версий перегруженных функций.

2 голосов
/ 06 января 2011

1) Есть ли рекомендуемый способ сделать это в целом?

Да, я бы сделал это так, как вы это сделали в 2).Я не думаю, что есть более глубокий смысл относительно того, почему 2) работает.Тип int просто не соответствует T*, поэтому он не может найти T.Поэтому он будет игнорировать шаблон.

...