c++ - 诸如 `msg(long)` 与候选 `msg(int32_t)` 和 `msg(int64_t)` 等函数的模糊重载

标签 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;
}

最佳答案

Greg 一语中的:int32_tint64_t 是类型定义,可能也可能不长。如果两者都不是 long 的类型定义,重载解析可能会失败。 long->int32_tlong->int64_t都有Rank=Promotion(表12、13.3.3.1.2)

关于c++ - 诸如 `msg(long)` 与候选 `msg(int32_t)` 和 `msg(int64_t)` 等函数的模糊重载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10579544/

相关文章:

c++ - 从文本文件中提取单个句子......我还没有做对

c++ - 在 C++ 中创建大小为 1000000000 的数组给了我以下错误。请帮助我理解并解决它

c++ - 无法将我的对象推送到 std::vector - gcc 找不到类似复制构造的东西

c++ - 使用位置无关代码按值和指针传递

windows - 可能和不太可能的宏

c++ - 为什么要在函数中使用 c_str()

c++ - 在初始化/激活 ActiveX 控件后,如何获取该控件的 HWND?

C++ 程序流程 : Sockets in an Object and the Main Function

c - 使用uclibc时如何解决fenv.h中对函数的 undefined reference ?

c++ - openmp g++错误: collapsed loops not perfectly nested