3

この質問には、(間接的に) 式テンプレートが関係しているため、C++ テンプレート メタプログラミングの知識が必要です。式テンプレートに関する直接的な質問ではなく、C++ 型の計算が含まれるため、間接的に言います。それが何かわからない場合は、この質問に答えないでください。

十分な背景情報なしに質問を出すことを避けるために、私が解決しようとしている一般的な問題について少し詳しく説明してから、より具体的な部分に進みます。

Integerユーザーが s と同じように計算できる s を提供するライブラリがあるとしますintIntegerさらに、からを構築することが可能intです。と同じように:

Integer<int> i(2);

内部的には、私のIntegerクラスはクラス テンプレートです:

template<class T>
class Integer {
  // cut out
};

したがって、好きな整数型で定義できます。

API を変更せずに、ライブラリを変更して、Integerから構築された場合int、別の型 (たとえば ) で内部的に表現する必要があるようにしたいと思いますIntegerLit。この理由は、 のインスタンスが(ベース ポインター + 個別のデータによって記述される一般的なオブジェクトとしてではなく、引数として関数に渡すことができる)Integerから作成されたことを知っていると、一部の計算を高速化できるためです。コメント。)intint

から構築する場合は型が異なることが不可欠です。これはint、コンパイラが an から構築されたかどうかに応じて異なるコード パスを使用する必要があるためですint。ランタイム データ フラグを使用してこれを行うことはできません。(要するに、コンパイラは、intタイプに応じて、または上記のより一般的なタイプのオブジェクトを取る関数を生成します。)

これを言うと、私は問題に遭遇します:使用が次のようなことをするとき:

Integer<int> a,b(2);

a = b + b;

ここaには、一般的なものIntegerb専門的なものがありIntegerLitます。Integerただし、私の問題は、ユーザーが変数を定義するためにまったく同じ型を自由に使用できるため、これを C++ で表現する方法です。

型をポリモーフィックにする、つまり派生元は機能IntegerLitIntegerません。一瞬元気そうです。Integerただし、ユーザーは(基本クラス) のインスタンスを作成するため、それは基本クラスであるため、コンパイラーは式ツリーに固執します (これが、式テンプレートが問題に関与する理由です)。したがって、この 2 つのケースを区別することはできません。動的キャストで RTTI チェックを行うことは、その時点で私が望んでいることではありません。

より有望なのは、リテラルテンプレートパラメーターbool litを型に追加して、それがから構築されたintかどうかを示しているようです。ポイントは、リテラルでないものには変換規則を指定せず、他の場合には指定することです。

しかし、私はそれを機能させることができません。次のコードは、int. trueそれ以外の場合、 の値としてInteger が指定されていないため、失敗しますlit。そのため、コンパイラは変換規則を持たないデフォルトの実装を検索します。API を変更するオプションではなく、Integer<int,true>から構築するときに記述する必要がありintます。

template<class T,bool lit=false>
class Integer
{
public:
  Integer() {
    std::cout << __PRETTY_FUNCTION__ << "\n";
  }
  T F;
};

template<>
template<class T>
class Integer<T,true>
{
public:
  Integer(int i) {
    std::cout << __PRETTY_FUNCTION__ << "\n";
  }
  T F;
};

このようなことが C++ で可能かどうか疑問に思い始めています。

ここで役立つ C++11 の新機能はありますか?

4

3 に答える 3

5

いいえ、これは C++ の仕組みではありません。bとして定義するとInteger b、それはInteger. これは、後で初期化するために使用される式に関係なく適用されますb

また、次のことも考慮してくださいextern Integer b;。を初期化する式がどこかにありますがb、コンパイラはまだここで型bが何であるかを把握する必要があります。(「持つ」ではなく「持つ」)。

于 2012-11-02T15:18:57.897 に答える
3

とにかく、それはできません。しかし、「自動」を使用すると、近づくことができます。

// The default case
Integer<int> MakeInt()
{
    return Integer<int>();
}

// The generic case
template <class T>
Integer<T> MakeInt(T n)
{
    return Integer<T>(n);
}

// And specific to "int"
Integer<IntegerLit> MakeInt(int n)
{
    return Integer<IntegerLit>(n);
}

auto a = MakeInt();
auto b = MakeInt(2);
auto c = MakeInt('c');
auto d = MakeInt(2.5);
于 2012-11-02T15:34:48.293 に答える
1

そんなことはできません。Integer<int>変数が変数の型であると言ったら。できることIntegerは、次のように、使用されるコンストラクターに応じて、基になる担当者を変更することです。

template<class T>
class Integer {
  // cut out
    Integer() : rep_(IntRep()) {}
    explicit Integer(int val) : rep_(IntLitRep(val)) {}

private:
    boost::variant<IntRep, IntLitRep> rep_;
};

次に、アクティブなバリアント バージョンを簡単に特定し、必要に応じてさまざまなコード パスを利用できます。

編集: この場合、の型はInteger同じですが、テンプレート関数を使用して、2 つの別個の型として動作しているように見せることが簡単にできます (担当者が有効な型を変更するため)。

于 2012-11-02T16:04:49.783 に答える