19

Nim プログラミング言語とは異なる型を C++ でエミュレートしようとしています。次の例は Nim でコンパイルされません。これは、バイナリ レベルではどちらも float であるにもかかわらず、コンパイラが変数をキャッチし、 異なる型 ( ) を持っているためです。edError: type mismatch: got (Euros, float)

type
  Euros = distinct float

when isMainModule:
  var
    e = Euros(12.34)
    d = 23.3
  echo (e + d)

C++ でこれを行う 1 つの方法は、float のラッパー クラスを作成することです。ただし、サイズが float と同じではないため、型をエクスポートする API ではうまく機能しません。または、クラスのサイズが float のストレージ長と一致しても、char 型のサイズと一致することはありません。これは、加算、減算などの演算に可能なすべての演算子も実装する場合に機能しますが、多くの入力とコードの複製が必要です。

新しいプリミティブ型の作成のような古い質問 には、ブーストの強力な typedef を使用するための受け入れられた回答があります。ただし、typedef は関数型シグネチャに対してのみ機能するようです。typedef は、float で継承された 2 つの型が一緒に追加され、それらの型が完全に変更されることを防ぎません (新しい型の錯覚があるだけなので)。

#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()署名が一致しないため、呼び出しは機能しませんが、言語では、他の操作で型を自由にマングルできます。

同じ回答で C++0x が強力な typedef をもたらすと言及されているので、この新しいサポートを探したところ、Bjarne Stroustrup 自身が 2012 年に C++11 スタイルの基調講演を行っていることがわかりました。21 分頃、彼はこれらの新しい強力な typedef について話し始めます。スライドだけをダウンロードすると、19 ページでSI 単位についての説明が始まり、その後 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;
}

コマンドラインで最新のXcode 5.1.1を使用してMacOSXでこれをコンパイルしようとしています:

$ g++ unit.cpp -std=c++11
unit.cpp:13:25: error: constexpr function's 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's 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.

スライドに示されている例と、さらにコードが不足している可能性がありますか? Bjarne が実証しようとしていたことの完全な例を誰かが持っていますか?

4

5 に答える 5