我尝试实现一个涉及模板的用户定义类型转换的小例子。
#include <cassert>
#include <cstdint>
#include <iostream>
#include <stdexcept>
#include <type_traits>
template <typename T>
concept bool UIntegral = requires() {
std::is_integral_v<T> && !std::is_signed_v<T>;
};
class Number
{
public:
Number(uint32_t number): _number(number)
{
if (number == 1) {
number = 0;
}
for (; number > 1; number /= 10);
if (number == 0) {
throw std::logic_error("scale must be a factor of 10");
}
}
template <UIntegral T>
operator T() const
{
return static_cast<T>(this->_number);
}
private:
uint32_t _number;
};
void changeScale(uint32_t& magnitude, Number scale)
{
//magnitude *= scale.operator uint32_t();
magnitude *= scale;
}
int main()
{
uint32_t something = 5;
changeScale(something, 100);
std::cout << something << std::endl;
return 0;
}
我收到以下编译错误(来自GCC 7.3.0):
main.cpp:在函数'void changeScale(uint32_t&amp;,Number)'中:
main.cpp:40:15:错误:'operator * ='不匹配(操作数类型为'uint32_t {aka unsigned int}'和'Number')
幅度* =比例;
注意该行已注释掉 - 这个有效:
//magnitude *= scale.operator uint32_t();
为什么不能自动推导模板化转换运算符?在此先感谢您的帮助。
[编辑]
我遵循删除概念的建议来使用Clang并查看其错误消息。我得到了以下内容(这是截断但足够的):
main.cpp:34:15: error: use of overloaded operator '*=' is ambiguous (with operand types 'uint32_t'
(aka 'unsigned int') and 'Number')
magnitude *= scale;
~~~~~~~~~ ^ ~~~~~
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, float)
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, double)
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, long double)
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, __float128)
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, int)
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, long)
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, long long)
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, __int128)
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, unsigned int)
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, unsigned long)
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, unsigned long long)
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, unsigned __int128)
因此,在开启概念之后,我假设强制转换数字的唯一方法是将其用于无符号整数类型 - 那么为什么编译器不能推断转换呢?
答案 0 :(得分:1)
requires
概念表达式的工作方式与SFINAE类似,它仅检查表达式有效,但不对其进行评估。
要让概念实际上将 T
限制为无符号整数类型,请使用bool
表达式:
template<typename T>
concept bool UIntegral = std::is_integral_v<T> && !std::is_signed_v<T>;
这会解决你的问题吗?不幸的是,请继续阅读...
为什么不能自动推导模板化转换运算符?
编写有缺陷的C ++代码是确定编译器错误的可靠方法:-) gcc中有超过1,000个已确认的未解决的错误。
是找到了模板化转化运算符should be,而"no match for 'operator*='"
错误消息应改为"ambiguous overload for 'operator*='"
。
所以,在开启概念的情况下,我假设强制转换数字的唯一方法是将其转换为无符号整数类型 - 那么为什么编译器不能推断转换呢?
即使概念要求和编译器错误得到修复,模糊性仍然存在,特别是这四个:
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, unsigned int)
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, unsigned long)
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, unsigned long long)
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, unsigned __int128)
这是因为每个可以想象的促销内置类型都有a lot个内置运算符,int
,long
,long long
和{ {1}}都是整数类型。
出于这个原因,通常不是一个好主意来将转换模板化为内置类型。
解决方案1。制作转换运算符模板__int128
并明确请求转换
explicit
解决方案2。只需实现 magnitude *= static_cast<uint32_t>(scale);
// or
magnitude *= static_cast<decltype(magnitude)>(scale);
类型的非模板化转换:
_number