Как разрешить неоднозначность вызова перегруженной функции с помощью литерала 0 и указателя
Я уверен, что это, должно быть, уже было здесь, но я не нашел много информации о том, как решить эту проблему (без кастования вызова):
Учитывая две перегрузки, я хочу, чтобы вызов с функцией с литералом 0 всегда вызывал неподписанную версию 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 )!
Ответы
Ответ 1
1) Есть ли рекомендуемый способ сделать это в целом?
Да, я сделал бы это так, как вы делали в 2). Я не думаю, что есть более глубокое значение, почему 2) работает. Тип int
просто не соответствует T*
, поэтому он не может найти T
. Он будет игнорировать шаблон.
Ответ 2
Что вы делаете в 2) работает и, вероятно, лучший способ это сделать.
В ситуациях, когда вы не хотите изменять функции, вы можете сделать явный приведение, чтобы дать компилятору подсказку:
func((void *) 0);
func((unsigned int) 0);
Ответ 3
Я предлагаю вам посмотреть нулевой указатель из С++ 0x (см. this). Он определяет класс, представляющий нулевые указатели любого типа. Пример, который вы только что дали, был на самом деле одним из мотивов включения nullptr_t (класса)/nullptr (значение) в С++ 0x. Фактически это позволяет вам устранить этот вызов, поставив 0, когда захочет беззнаковая версия int, и nullptr, если вы хотите другой.
Вы можете просто реализовать этот трюк в небольшом классе утилиты, пока ваш компилятор его не поддержит (или просто используйте его, если ваш компилятор реализует эту часть следующего стандарта).
Ответ 4
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) Есть ли какие-либо проблемы с этим следующим образом и в чем причина этого?
Шаблонный трюк работает, потому что правила для разрешения вызовов перегруженных функций и шаблонных версий предназначены для предпочтения не templated версий перегруженных функций.