对"uint32_t"的暧昧呼唤"long unsigned int"



我有一堆针对所有[u]int{8|16|32|64}_t类型重载的函数:

std::string f( uint8_t) { /*something*/ }
std::string f(  int8_t) { /*something*/ }
std::string f(uint16_t) { /*something*/ }
std::string f( int16_t) { /*something*/ }
std::string f(uint32_t) { /*something*/ }
std::string f( int32_t) { /*something*/ }
std::string f(uint64_t) { /*something*/ }
std::string f( int64_t) { /*something*/ }
//A few more overloads with a few more types (bool, float, const char*, etc.)

我现在用类型 long unsigned int 的参数调用函数名称:

template <typename type_blah> class Something { public:
        //...
        std::string call_f(void) const {
            return f(*((type_blah*)(internal_variable)));
        }
        //...
};

这会产生一个错误:

错误:重载的"f(long unsigned int&)"的调用不明确


我想,发生这种情况是因为unsigned intuint32_t是不同的类型。 但是,我不能为long unsigned int重载函数,因为这是一个多余的定义。 即:

std::string f(long unsigned int) { /*something*/ }

。生产:

错误:"std::字符串 f(uint32_t)"之前在此处定义


似乎类型机制是相互对抗的:它无法确定使用哪个转换,因为每个转换都同样有效,但无法定义无转换重载,因为它已经有效。

由于各种原因,我无法提出论点。 有没有办法摆脱这种情况?

平台是运行在Windows 7 x86-64上的g ++ MinGW x86。

您使用什么平台?

在Windows(Visual Studio 2010)上,unsigned long int与您提到的其他类型不同。

专门为该类型添加重载解决了错误。 这个答案(和/或谷歌)可能会更清楚地说明这个问题:未签名长整型的类型与Windows(VS2010)上的uint32_t和uint64_t不同。

我为unsigned long int定义了一个重载,如下所示:

std::string f( unsigned long int val )
{
  // Check that we chose the correct corresponding type
  // (This may vary by platform!)
  assert( sizeof( unsigned long int ) == sizeof( uint32_t ) );
  return f( static_cast<uint32_t>( val ) );
}

。在Visual Studio 2010中进行了如下测试:

void main()
{
  std::cout << "sizeof( unsigned long int ): " << sizeof( unsigned long int ) << std::endl;
  std::cout << "sizeof( uint32_t ): "          << sizeof( uint32_t )          << std::endl;
  unsigned long int x = 1u;
  std::cout << f( x ) << std::endl;
}

。并得到了预期的结果:

sizeof( unsigned long int ): 4
sizeof( uint32_t ): 4
uint32_t

以下是我基于上面提供的代码的"测试":

#include <string>
#include <cstdint>
#include <iostream>
std::string f( uint8_t) { return "ui8";}
std::string f(  int8_t) { return "i8";}
std::string f(uint16_t) { return "ui16";}
std::string f( int16_t) { return "i16";}
std::string f(uint32_t) { return "ui32";}
std::string f(unsigned long long int) { return "unsigned long long";}
std::string f(unsigned long int) { return "unsigned long";}
std::string f( int32_t) { return "i32";}
//std::string f(uint64_t) { return "ui64";}
std::string f( int64_t) { return "i64";}
int main()
{
    unsigned long x = 42;
    unsigned y = 17;
    uint32_t z = 9;
    uint64_t w = 135;
    std::cout << "x: "<< f(x) << " y: " << f(y) << " z: " << f(z) << " w: " << f(w) << std::endl;
}

示例输出:

$ clang++ ambig.cpp -std=c++0x -Wall -m64
$ ./a.out 
x: unsigned long y: ui32 z: ui32 w: unsigned long
$ clang++ ambig.cpp -std=c++0x -Wall -m32
$ ./a.out 
x: unsigned long y: ui32 z: ui32 w: unsigned long long

(我用 clang++ 复制了我的运行,但 g++ 的结果是一样的)

这可确保涵盖unsigned longunsigned long long类型。不幸的是,其中之一是 uint64_t ,因此必须将其删除。

如果你确实将变量声明为 unsigned long ,你必须提供一个完全接受它的函数 - 并且依赖它等同于uint32_t可能是不正确的 - 即使它们是相同的位大小。

既然你正在为(几乎?)每种类型定义重载,也许你的函数应该是一个模板?

template < typename T >
std::string f( T )
{
  /*something*/
}

如果有一组代码适用于所有(甚至大多数)类型,那也会为您节省大量工作。

如果出于某种原因,您仍然需要强制使用 unsigned long int 值的调用将其视为其他类型(如 uint32_t ),则可以在调用站点指定模板实例化:

return f<uint32_t>( *internal_variable );

最新更新