1

寸法の正確さを強制するテンプレート クラスを作成しようとしています (長さを時間で割ると速度が得られるなど)。

短編小説:「無次元」は可能なインスタンス化の 1 つです。すべてのインスタンス化を double から明示的に構築できるようにし、さらに "無次元" インスタンス化 (および無次元インスタンス化のみ) を double から暗黙的に構築できるようにすると便利です。

長い話:私のテンプレートクラスは次のようにレイアウトされています

template<int iLength, int iTime, int iMass>
class qty {
   double data;

   //Operators overloaded to enforce dimensional correctness
   //  e.g. qty<a,b,c> can only be added to qty<a,b,c>
   //       qty<a,b,c> * qty<a2,b2,c2> returns qty<a+a2,b+b2,c+c2>

};

このスタイルに従えば、は無次元量なので、aと doubleqty<0,0,0>を足したり引いたりできるはずです。qty<0,0,0>私は現在、宣言することでこれを強制しています

    qty operator+ (const double& rhs) const;

...しかし、それを定義するだけですqty<0,0,0>。これは実行可能ですが、もっとうまくできると思います。double から への暗黙的な変換を許可した場合qty<0,0,0>、 double と の追加はqty<0,0,0>特別な処理を必要としません。ユーザーの間違いも、より示唆的なエラー メッセージを表示します --- 速度に double を追加しようとすると、関数が定義されていないと不平を言うのではなく、変換が不可能であることを示します (次元の非互換性の根底にある考えに到達します)。これにより、ユーザーはテンプレート クラスのエラーを疑う可能性があります)。

問題は、テンプレート パラメーターの他の組み合わせに対して暗黙的な構築を許可できないことです。そうした場合、qty と double の追加は常に成功します。ユーザーに次元の正確さについて考えさせ、加算する前に double 定数を適切な次元に明示的に変換するようにします (それが意図した操作である場合)。ただし、double からの明示的な構築を許可したい--- それがなければ、単純な宣言

qty<1,-1,0> a(1.5); //speed with value 1.5

厄介な変換関数が必要になります

qty<1,-1,0> a = makeQty<1,-1,0>( 1.5 ); //my eyes hurt

つまり、私が本当に欲しいのは

template<int iLength, int iTime, int iMass>
class qty {
    double data;
    explicit qty(const double& rhs) : data(rhs) {} //general version prohibits
                                                   //implicit conversion

    //...
};

template<>       
qty<0,0,0>::qty(const double&rhs) : data(rhs) {} //Explicit instantiation
                                                 //for dimensionless case
        // ... with black magic to reallow implicit conversion 
        // for this instantiation only ???

ご覧のとおり、1 つのインスタンス化のみの仕様を削除できるかどうかはわかりません。またexplicit、可能であれば、構文がどのようなものかわかりません。

4

2 に答える 2

1

Tbool に応じて、あるタイプまたは作成できないタイプを作成します。

template<bool b, typename T>
struct block_unless {
  struct type { type() = delete; operator T(); }; // operator T is standard-paranoia
};
template<typename T>
struct block_unless<true, T> {
  using type = T;
};
template<bool b, typename T>
using block_unless_t = typename block_unless<b,T>::type;
template<bool b, typename T>
using block_if_t = block_unless_t<!b, T>;

次に、残りのコードでインラインでブロック/アクティブ化するメソッドを保護します。

template<int a, int b, int c>
struct qty {
  enum { scalar = (a==0)&&(b==0)&&(c==0) };
  explict qty( block_if_t< scalar, double > d );
  qty( block_unless_t< scalar, double > d );
};

どのようにそのことについて?

C++1y では、require 句がおそらくより適切に機能します。

(標準的なパラノイアは、テンプレート メソッドが少なくとも 1 つの有効なインスタンス化を持たなければならないという標準の言い回しによるものです。到達不能でoperator Tあるとはd、コードがdouble.

于 2014-07-14T23:19:07.490 に答える
0

直接変更することはできませんが、以下は C++11 で機能します。

template<int iLength, int iTime, int iMass>
class qty_impl {
    double data;
public:
    explicit qty_impl(const double& rhs) : data(rhs) {} //general version prohibits
                                                        //implicit conversion

    //...
};

// general case: simply forward to _impl
template<int iLength, int iTime, int iMass>
class qty : public qty_impl<iLength,iTime,iMass> {
    // inherit ctors, including "explicit"
    using qty_impl<iLength,iTime,iMass>::qty_impl;
};

// special case
template<>
class qty<0,0,0> : public qty_impl<0,0,0> {
    using qty_impl<0,0,0>::qty_impl;
public:
    // provide non-explicit ctor to override the inherited base ctors
    qty(const double& rhs) : qty_impl<0,0,0>(rhs) {}
};

これにより、ほとんどすべての共通の実装を維持し、非明示的な ctor を明示的な ctor に単純に転送できます。

于 2014-07-14T21:43:37.850 に答える