Я разработал универсальный класс "Unsigned" или действительно шаблон класса Unsigned<size_t N>
, который моделирует после встроенных в C (C ++) неподписаний, используя в качестве параметра значение uint8_t
s.Например, Unsigned<4>
идентично uint32_t
, а Unsigned<32>
будет идентично uint256_t
- если оно существует.
До сих пор мне удавалось следовать большинству, если не всей семантикеожидается от встроенного unsigned - в частности sizeof(Natural<N>)==N
, (Natural<N>(-1) == "max_value_all_bits_1" == ~Natural<N>(0))
, совместимость с abs (), sign (), div (с использованием пользовательской структуры div_t), ilogb () (кажется, исключая GCC) и numeric_limits<>.
Однако я сталкиваюсь с проблемой, заключающейся в том, что, поскольку 1.- шаблон класса - это просто шаблон, поэтому шаблонные формы не связаны, и 2.- нетипизированный параметр шаблона требует «compile-постоянная времени ", которая намного строже, чем" a const
", я по существу не могу создать неподписанное с неизвестным N .
Другими словами, я не могуиметь такой код:
...
( ... assuming all adequate headers are included ...)
using namespace std;
using lpp::Unsigned;
std::string str;
cout<< "Enter an arbitrarily long integer (end it with <ENTER>) :>";
getline(cin, str, '\n');
const int digits10 = log10(str.length()) + 1;
const int digits256 = (digits10 + 1) * ceil(log(10)/log(256)); // from "10×10^D = 256^T"
// at this point, I "should" be able to, semantically, do this:
Unsigned<digits256> num; // <-- THIS I CAN'T -- num would be guaranteed
// big enough to hold str's binary expression,
// no more space is needed
Unsigned::from_str(num, str); // somehow converts (essentially a base change algo)
// now I could do whatever I wanted with num "as if" a builtin.
std::string str_b3 = change_base(num, 3); // a generic implemented somehow
cout<< "The number above, in base 3, is: "<< str_b3<< endl;
...
(A / N - это часть тестового набора для Unsigned, который читает «немного большое число» (я пробовал до 120 цифр - после установки Nсоответственно) и делает такие вещи, как выражение его в других основах, что само по себеуже проверяет все арифметические функции.)
В поисках возможных способов обойти или иным образом ослабить это ограничение, я столкнулся с некоторыми концепциями, которые я хотел бы попробовать и изучить, но я бы не хотелтратить слишком много усилий на альтернативу, которая только усложнит ситуацию или сделает поведение классов слишком большим.
Первое, что я подумал, было то, что если бы я не былв состоянии выбрать Unsigned<N>
по моему выбору, я мог бы по крайней мере выбрать из набора предварительно выбранных значений N, что привело бы к вызову адекватного конструктора во время выполнения, но в зависимости от значения времени компиляции:
???? GetMeAnUnsigned (size_t S) {
switch (S) {
case 0: { throw something(); } // we can't have a zero-size number, right?
case 1, 2, 3, 4: { return Unsigned<4>(); break; }
case 5, 6, 7, 8: { return Unsigned<8>(); break; }
case 9, 10, 11, 12, 13, 14, 15, 16: { return Unsigned<16>(); break; }
....
default: { return Unsigned<128>(); break; } // wow, a 1Kib number!
} // end switch
exit(1); // this point *shouldn't* be reachable!
} // end function
Мне лично этот подход нравится.Однако я не знаю, что я могу использовать, чтобы указать тип возвращаемого значения.На самом деле он не «решает» проблему, он лишь в некоторой степени снижает ее серьезность.Я уверен, что трюк с переключателем будет работать, так как экземпляры равны от константы времени компиляции, он только меняет , из которых будет иметь место.
Единственной жизнеспособной помощью для объявления возвращаемого типа является новая конструкция C ++ 0 (1?) X " decltype ", которая позволила бы мне получить адекватный тип, что-тонапример, если я правильно понял функцию:
decltype (Unsigned<N>) GetMeAnUnsigned (size_t S) {
.. do some choices that originate an N
return Unsigned<N>();
}
... или что-то в этом роде.Я еще не вошел в C ++? X за пределами auto
(для итераторов), поэтому первый вопрос будет таким: будут ли такие функции, как decltype
или auto
, помочь мне достичь того, чего я хочу? ( Runtime выбор экземпляров, даже если они ограничены)
В качестве альтернативы я подумал, что если бы проблема заключалась в отношении между моими классами, то я мог бы сделать их all"своего рода" Base, получая сам шаблон:
template <size_t N>
class Unsigned : private UnsignedCommon { ...
... но я оставил этот подход на заднем плане, потому что, ну, никто не делает , что (сделать все "своего рода") со встроенными модулями, плюс для случаев, когда один действительно фактически рассматривает их как общий класс, он требует инициализации статики, возврата указателей и оставления клиента для уничтожения, еслиЯ правильно помню.Тогда второй вопрос: я ошибся, отказавшись от этой альтернативы слишком рано?