7

注意:这与在编译时确定整数类型的位数非常相似,但是这是一个非常简化的版本,所有内容都包含在单个.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

解决方案

解决方案是提供一个成功映射的函数intlong并映射long long到适当的int32_tor int64_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;
}
4

2 回答 2

3

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

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

于 2012-05-14T08:16:11.090 回答
3

格雷格一针见血:int32_t并且int64_t是 typedef,可能是也可能不是long. 如果两者都不是 typedef long,则重载决议可能会失败。两者long->int32_t都有long->int64_tRank=Promotion (表 12, 13.3.3.1.2)

于 2012-05-14T09:42:53.283 回答