函数的模糊重载,如`msg(long)`与候选`msg(int32_t)`和`msg(int64_t)`

时间:2012-05-14 08:07:01

标签: c++ gcc

注意:这与Determine number of bits in integral type at compile time非常相似,但这是一个非常简化的版本,全部包含在一个.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 <iostream>
#include <stdint.h>

#include <boost/integer.hpp>

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

解决方案

该解决方案提供的功能可以成功将intlonglong long映射到相应的int32_tint64_t。这可以在运行时通过if (sizeof(int)==sizeof(int32_t))类型语句轻松完成,但最好是编译时解决方案。通过使用boost::enable_if可以获得编译时解决方案。

以下适用于MSVC10和gcc 4.6.3。 通过禁用非整数类型可以进一步增强解决方案,但这不在此问题的范围内。

#include <iostream>
#include <stdint.h>

#include <boost/integer.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_signed.hpp>
#include <boost/type_traits/is_unsigned.hpp>

using namespace std;

template <class InputT>
typename boost::enable_if_c<sizeof(InputT)==sizeof(int32_t) && boost::is_signed<InputT>::value,
 int32_t>::type ConvertIntegral(InputT z) { return static_cast<int32_t>(z); }

template <class InputT>
typename boost::enable_if_c<sizeof(InputT)==sizeof(int64_t) && boost::is_signed<InputT>::value, 
int64_t>::type ConvertIntegral(InputT z) { return static_cast<int64_t>(z); }

template <class InputT>
typename boost::enable_if_c<sizeof(InputT)==sizeof(uint32_t) && boost::is_unsigned<InputT>::value, 
uint32_t>::type ConvertIntegral(InputT z) { return static_cast<uint32_t>(z); }

template <class InputT>
typename boost::enable_if_c<sizeof(InputT)==sizeof(uint64_t) && boost::is_unsigned<InputT>::value, 
uint64_t>::type ConvertIntegral(InputT z) { return static_cast<uint64_t>(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;
}

2 个答案:

答案 0 :(得分:3)

代码是否编译是实现定义的。没有类型int32_t也没有int64_t;这些只是现有整数类型的typedef。如果类型恰好是已经过载的类型(intlonglong long),这几乎肯定是这种情况,那么您对同一函数有多个定义。如果它们在同一个翻译单元中,则是编译时错误,需要诊断。如果它们处于不同的转换单元中,则它是未定义的行为,但我认为大多数实现也会产生错误。

在您的情况下,最佳解决方案可能是使msg成为模板,并将类型的名称作为参数传递。

答案 1 :(得分:3)

Greg击中头部:int32_tint64_t是typedef,可能是也可能不是long。如果两者都不是long的typedef,则重载解析可能会失败。 long->int32_tlong->int64_t都有Rank = Promotion(表12,13.3.3.1.2)