Я пытаюсь эмулировать в С++ a distinct
типа из Nim
язык программирования. Следующий пример не будет
компилировать в Nim, потому что компилятор ловит переменные e
и d
имеющие разные типы (Error: type mismatch: got (Euros, float)
), несмотря на
оба являются float на двоичном уровне:
type
Euros = distinct float
when isMainModule:
var
e = Euros(12.34)
d = 23.3
echo (e + d)
Один из способов сделать это в С++ - это написать класс-оболочку для float. <Удаp > Но это не работает с API, которые экспортируют этот тип, потому что размер не будет быть таким же, как float. Или даже если размер класса соответствует длине хранения float, он никогда не будет соответствовать размеру типа char. Это будет работать, если вы также реализуете все возможные операторы для операций, таких как сложение, вычитание и т.д., но требует много типизации и дублирования кода.
Предыдущие вопросы типа Создание нового примитива типа имеют принятый ответ на использование boost strong typedef. Однако typedef похоже, работает только для сигнатур типа функции, typedef не будет препятствовать двум флоат-унаследованные типы, которые должны быть добавлены вместе, и их тип полностью изменился (ну, потому что есть только иллюзия нового типа):
#include <boost/serialization/strong_typedef.hpp>
#include <stdio.h>
BOOST_STRONG_TYPEDEF(float, money);
void test(money a, float b)
{
int t = a + b;
printf("value is %d", t);
}
int main()
{
money a(5.5);
int euros(5);
// This is not caught!
int dollars = a + euros;
printf("dollars %d\n", dollars);
// But the compiler catches this misuse.
test(euros, a);
}
Но что почти, вызов test()
не будет работать, потому что подпись
не соответствует, но язык по-прежнему позволяет другим операциям манипулировать типами
по желанию.
В том же ответе упоминается С++ 0x, чтобы принести сильные typedefs, поэтому я искал это новая поддержка и обнаружили, что Сам Бьярне Страуструп дал стиль С++ 11 основной 2012. Около минуты 21 он начинает говорить об этих новых сильных typedefs. если ты скачайте только слайды, страница 19 начнет говорить о единицах СИ и позже на стр. 22 и 23 упоминается, как это будет сделано. Однако я не смог заставьте примеры работать. Здесь лоскутное одеяло, которое мне удалось придумать:
template<int M, int K, int S> struct Unit { // a unit in the MKS system
enum { m=M, kg=K, s=S };
};
template<typename Unit> // a magnitude with a unit
struct Value {
double val; // the magnitude
explicit Value(double d) : val(d) {} // construct a Value from a double
};
using Meter = Unit<1,0,0>; // unit: meter
using Second = Unit<0,0,1>; // unit: sec
using Speed = Value< Unit<1,0,-1> >; // meters/second type
constexpr Value<Second> operator "" _s(long double d)
// a f-p literal suffixed by ‘_s’
{
return Value<Second> (d);
}
constexpr Value<Meter> operator "" _m(long double d)
// a f-p literal suffixed by ‘_m’
{
return Value<Meter> (d);
}
int main(void)
{
Speed sp1 = 100_m / 9.8_s;
return 42;
}
Я пытаюсь скомпилировать это под MacOSX с последним Xcode 5.1.1 с командной строкой:
$ g++ unit.cpp -std=c++11
unit.cpp:13:25: error: constexpr function return type 'Value<Second>' is not a
literal type
constexpr Value<Second> operator "" _s(long double d)
^
unit.cpp:5:8: note: 'Value<Unit<0, 0, 1> >' is not literal because it is not an
aggregate and has no constexpr constructors other than copy or move
constructors
struct Value {
^
unit.cpp:18:24: error: constexpr function return type 'Value<Meter>' is not a
literal type
constexpr Value<Meter> operator "" _m(long double d)
^
unit.cpp:5:8: note: 'Value<Unit<1, 0, 0> >' is not literal because it is not an
aggregate and has no constexpr constructors other than copy or move
constructors
struct Value {
^
unit.cpp:26:20: error: no matching literal operator for call to 'operator "" _m'
with argument of type 'unsigned long long' or 'const char *', and no
matching literal operator template
Speed sp1 = 100_m / 9.8_s;
^
unit.cpp:26:28: error: no matching literal operator for call to 'operator "" _s'
with argument of type 'long double' or 'const char *', and no matching
literal operator template
Speed sp1 = 100_m / 9.8_s;
^
4 errors generated.
Возможно, примеры, приведенные в слайдах, и мне не хватает кода? Есть ли у кого-нибудь полный пример того, что Бьярн пытался продемонстрировать?