Неоднозначная перегрузка функций, таких как `msg(long)` с кандидатами `msg(int32_t)` и `msg(int64_t)`

Примечание: Это очень похоже на Определить количество битов в целочисленном типе во время компиляции, однако это сильно упрощенная версия, содержащаяся в одном .cpp

Редактировать: добавлено решение - хотя было дано (и принято) правильное объяснение, я нашел способ решить проблему в общем.

Проблема

Проблема с такими функциями, как

 msg(int32_t);
 msg(int64_t);

вызов типа

long long myLong = 6;
msg(myLong);    // Won't compile on gcc (4.6.3), call is ambiguous

Это компилируется на MSVC.Может ли кто-нибудь объяснить, почему это не работает на gcc (я предполагаю, что это, вероятно, связано с тем фактом, что gcc обычно строго соответствует стандартам) и пример того, как правильно добиться того же эффекта?

#include 
#include 

#include 

using namespace std;

void msg(int v) { cout << "int: " << sizeof(int) << ' ' << v << '\n'; }
void msg(long v) { cout << "long: " << sizeof(long) << ' ' << v << '\n'; }
void msg(long long v) { cout << "long long: " << sizeof(long long) << ' ' << v << '\n'; }

void msg2(int32_t v) { cout << "int32_t: " << sizeof(int32_t) << ' ' << v << '\n'; }
void msg2(int64_t v) { cout << "int64_t: " << sizeof(int64_t) << ' ' << v << '\n'; }
void msg2(uint32_t v) { cout << "uint32_t: " << sizeof(uint32_t) << ' ' << v << '\n'; }
void msg2(uint64_t v) { cout << "uint64_t: " << sizeof(uint64_t) << ' ' << v << '\n'; }


int main()
{

    int myInt = -5;
    long myLong = -6L;
    long long myLongLong = -7LL;

    unsigned int myUInt = 5;
    unsigned int myULong = 6L;
    unsigned long long myULongLong = 7LL;

    msg(myInt);
    msg(myLong);
    msg(myLongLong);

    msg2(myInt);
    msg2(myLong);     // fails on gcc 4.6.3 (32 bit)
    msg2(myLongLong);

    msg2(myUInt);
    msg2(myULong);   // fails on gcc 4.6.3 (32 bit)
    msg2(myULongLong);

   return 0;
}

// Output from MSVC  (and gcc if you omit lines that would be commented out)
int: 4 5
long: 4 6
long long: 8 7
int32_t: 4 -5
int32_t: 4 -6   // omitted on gcc
int64_t: 8 -7
uint32_t: 4 5
uint32_t: 4 6   // omitted on gcc
uint64_t: 8 7

Решение

Решение заключается в предоставлении функции, которая успешно отображает int, longи long longв соответствующий int32_tили int64_t. Это можно сделать тривиально во время выполнения с помощью операторов типа if (sizeof(int)==sizeof(int32_t)), но предпочтительнее решение на этапе компиляции. Решение времени компиляции доступно с помощьюboost::enable_if.

Следующее работает с MSVC10 и gcc 4.6.3. Решение можно улучшить, отключив нецелочисленные типы, но это выходит за рамки данной проблемы.

#include 
#include 

#include 
#include 
#include 
#include 

using namespace std;

template 
typename boost::enable_if_c::value,
 int32_t>::type ConvertIntegral(InputT z) { return static_cast(z); }

template 
typename boost::enable_if_c::value, 
int64_t>::type ConvertIntegral(InputT z) { return static_cast(z); }

template 
typename boost::enable_if_c::value, 
uint32_t>::type ConvertIntegral(InputT z) { return static_cast(z); }

template 
typename boost::enable_if_c::value, 
uint64_t>::type ConvertIntegral(InputT z) { return static_cast(z); }

void msg(int v) { cout << "int: " << sizeof(int) << ' ' << v << '\n'; }
void msg(long v) { cout << "long: " << sizeof(long) << ' ' << v << '\n'; }
void msg(long long v) { cout << "long long: " << sizeof(long long) << ' ' << v << '\n'; }


void msg2(int32_t v) { cout << "int32_t: " << sizeof(int32_t) << ' ' << v << '\n'; }
void msg2(int64_t v) { cout << "int64_t: " << sizeof(int64_t) << ' ' << v << '\n'; }
void msg2(uint32_t v) { cout << "uint32_t: " << sizeof(uint32_t) << ' ' << v << '\n'; }
void msg2(uint64_t v) { cout << "uint64_t: " << sizeof(uint64_t) << ' ' << v << '\n'; }

int main()
{

    int myInt = -5;
    long myLong = -6L;
    long long myLongLong = -7LL;

    unsigned int myUInt = 5;
    unsigned int myULong = 6L;
    unsigned long long myULongLong = 7LL;

    msg(myInt);
    msg(myLong);
    msg(myLongLong);

    msg2(ConvertIntegral(myInt));
    msg2(ConvertIntegral(myLong));
    msg2(ConvertIntegral(myLongLong));

    msg2(ConvertIntegral(myUInt));
    msg2(ConvertIntegral(myULong));
    msg2(ConvertIntegral(myULongLong));

   return 0;
}

7
задан Community 23 May 2017 в 10:09
поделиться