理解编译器在解决函数重载时的选择
Understanding compiler choice in resolving function overloading
我在 int= 32 位(gcc arm none eabi、cortex M3、GCC 版本 9)的平台上编译,方言设置为 C++17。
我有一个重载方法,其中包含同一方法的模板版本和普通版本。正常重载位于私有基 class 中,但已通过 using 子句公开。
class MemoryStream {
public:
inline void write(bool value);
inline void write(uint8_t value);
inline void write(uint16_t value);
inline void write(uint32_t value);
inline void write(int16_t value);
inline void write(int32_t value);
}
和
class WriteStream :private MemeoryStream {
public:
using MemoryStream::write;
template<typename T>
typename std::enable_if<std::is_integral<T>::value>::type WriteStream::write(T obj){
MemoryStream::write(obj);
}
}
当我使用数字文字调用方法时,即
txStream.write(0U);
我收到以下错误:
In instantiation of 'typename std::enable_if<std::is_integral<_Tp>::value>::type WriteStream::write(T) [with T = unsigned int; typename std::enable_if<std::is_integral<_Tp>::value>::type = void]':
error: call of overloaded 'write(unsigned int&)' is ambiguous
1.) 为什么没有选择普通重载函数,因为它们是通过 using 子句导入的,如果我调用
txStream.write<uint32_t>(0U);
或
constexpr uint32_t Zero =0;
txStream.write<uint32_t>(Zero);
他们正确无误地解决了?
unsigned int 是否与 uint32_t 不同?
2.) 为什么编译器将数字文字转换为引用???如错误信息所示:'call of overloaded write(unsigned int&) is ambiguous'
unsigned int
是与固定宽度类型不同的类型(即使其中一个类型固定的类型将具有与 unsigned int
相同的大小),因此对于您的代码,编译器不会不知道应该调用 write
的哪个重载。
您需要为 unsigned int
和 int
提供重载。
考虑一下如果在一个系统上使用 32 位整数调用 write(uint32_t)
而在另一个具有 16 位整数的系统上 完全相同的代码 会调用 write(uint16_t)
(或用“64”代替“16”)。或者如果一个系统写入 32 位数字而另一个系统读取不同大小的数字,则会出现相应的混乱。
您收到不明确的重载错误的原因是,unsigned int
可以 隐式转换为 MemoryStream::write
的任何重载参数类型.由于 unsigned int
没有直接重载,编译器不知道 select:
哪个重载
template<typename T>
typename std::enable_if<std::is_integral<T>::value>::type WriteStream::write(T obj){
//which overload for MemoryStream::write should be selected here?
MemoryStream::write(obj);
}
如果您显式声明模板参数 txtStream.write<uint32_t>(0U);
,则不会发生这种情况,因为参数 0L
会隐式转换为 uint32_t
。由于存在 uint32_t
的 MemoryStream::write
的直接重载,因此您不会收到任何歧义错误。
至于你的第二个问题,在 WriteStream::write
的正文中,obj
是对 unsigned int
的左值引用,尽管从你的初始函数调用开始:txtStream.write(0L)
参数是一个数字文字:
template<typename T>
typename std::enable_if<std::is_integral<T>::value>::type WriteStream::write(T obj){
//obj is an lvalue reference within this scope to whatever T is
// deduced to be (unsigned int in your example)
MemoryStream::write(obj);
}
我在 int= 32 位(gcc arm none eabi、cortex M3、GCC 版本 9)的平台上编译,方言设置为 C++17。
我有一个重载方法,其中包含同一方法的模板版本和普通版本。正常重载位于私有基 class 中,但已通过 using 子句公开。
class MemoryStream {
public:
inline void write(bool value);
inline void write(uint8_t value);
inline void write(uint16_t value);
inline void write(uint32_t value);
inline void write(int16_t value);
inline void write(int32_t value);
}
和
class WriteStream :private MemeoryStream {
public:
using MemoryStream::write;
template<typename T>
typename std::enable_if<std::is_integral<T>::value>::type WriteStream::write(T obj){
MemoryStream::write(obj);
}
}
当我使用数字文字调用方法时,即
txStream.write(0U);
我收到以下错误:
In instantiation of 'typename std::enable_if<std::is_integral<_Tp>::value>::type WriteStream::write(T) [with T = unsigned int; typename std::enable_if<std::is_integral<_Tp>::value>::type = void]':
error: call of overloaded 'write(unsigned int&)' is ambiguous
1.) 为什么没有选择普通重载函数,因为它们是通过 using 子句导入的,如果我调用
txStream.write<uint32_t>(0U);
或
constexpr uint32_t Zero =0;
txStream.write<uint32_t>(Zero);
他们正确无误地解决了?
unsigned int 是否与 uint32_t 不同?
2.) 为什么编译器将数字文字转换为引用???如错误信息所示:'call of overloaded write(unsigned int&) is ambiguous'
unsigned int
是与固定宽度类型不同的类型(即使其中一个类型固定的类型将具有与 unsigned int
相同的大小),因此对于您的代码,编译器不会不知道应该调用 write
的哪个重载。
您需要为 unsigned int
和 int
提供重载。
考虑一下如果在一个系统上使用 32 位整数调用 write(uint32_t)
而在另一个具有 16 位整数的系统上 完全相同的代码 会调用 write(uint16_t)
(或用“64”代替“16”)。或者如果一个系统写入 32 位数字而另一个系统读取不同大小的数字,则会出现相应的混乱。
您收到不明确的重载错误的原因是,unsigned int
可以 隐式转换为 MemoryStream::write
的任何重载参数类型.由于 unsigned int
没有直接重载,编译器不知道 select:
template<typename T>
typename std::enable_if<std::is_integral<T>::value>::type WriteStream::write(T obj){
//which overload for MemoryStream::write should be selected here?
MemoryStream::write(obj);
}
如果您显式声明模板参数 txtStream.write<uint32_t>(0U);
,则不会发生这种情况,因为参数 0L
会隐式转换为 uint32_t
。由于存在 uint32_t
的 MemoryStream::write
的直接重载,因此您不会收到任何歧义错误。
至于你的第二个问题,在 WriteStream::write
的正文中,obj
是对 unsigned int
的左值引用,尽管从你的初始函数调用开始:txtStream.write(0L)
参数是一个数字文字:
template<typename T>
typename std::enable_if<std::is_integral<T>::value>::type WriteStream::write(T obj){
//obj is an lvalue reference within this scope to whatever T is
// deduced to be (unsigned int in your example)
MemoryStream::write(obj);
}