Я попытался реализовать небольшой пример преобразования пользовательского типа с использованием шаблонов.
#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 &, Number)»:
main.cpp: 40: 15: error: нет соответствия для «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)
Итак, включив концепции, я предполагаю, что единственный способ привести число к типу беззнаковый интеграл - тогда почему компилятору недостаточно для вывода преобразования?
std::is_integral_v<T> && !std::is_signed_v<T>
было допустимым выражением; он не предъявляет никаких требований к значению этого выражения. Вместо этого вы почти наверняка захотитеtemplate<typename T> concept bool UIntegral = std::is_integral_v<T> && !std::is_signed_v<T>;
. - person Casey   schedule 04.04.2018