1

仮想の可変個引数テンプレート タプル クラスは、私が知る限り、テンプレート パラメーターでゲッターを使用する必要があります。

int MyInt = MyTuple.Get<int>(0);

これは不便であり、エラーが発生する可能性があります。クラスを明示的に指定する必要がないように、クラスを構築する方法があると感じずにはいられません。

int MyInt = MyTuple.Get(0);

私が最初に考えたのは、おそらく何らかの事前計算済みリストの値Get()と比較することによって、型を独自に把握する別のクラスをメンバー関数が返すことでした。typeid(Foo).name()ただし、これはまだ実行前に実行する必要があり、コンパイル時にそのような処理を繰り返す方法がわかりませんでした。

タプルのように、型を明示的に指定する必要のないゲッターを持つ方法はありますか?

4

7 に答える 7

7

あなたは好きstd::tupleですか?

ゲッターのテンプレート引数は、タイプではなく、メンバーのインデックスを指定します。定義上、タプルの数とタイプはコンパイル時に固定されます。タイプはインデックスに依存し、コンパイル時にタイプがわかっている必要があるため、ゲッターはテンプレート化する必要があります。

template< typename ... types >
struct tuple;

template< typename head, typename ... tail_types >
struct tuple {
    head value;
    tuple< tail_types ... > tail;
};

template<>
struct tuple<> {};

template< typename tuple, size_t index >
struct tuple_element;

template< typename head, typename ... tail, size_t index >
struct tuple_element< tuple< head, tail ... >, index >
    { typedef typename tuple_element< tail ..., index - 1 >::type type; };

template< typename head, typename ... tail >
struct tuple_element< tuple< head, tail ... >, 0 >
    { typedef head type; };

template< size_t index, typename tuple >
typename std::enable_if< index != 0, 
                   typename tuple_element< tuple, index >::type >::type
get( tuple const &t )
    { return get< index - 1 >( t.tail ); }

template< size_t index, typename tuple >
typename std::enable_if< index == 0,
                   typename tuple_element< tuple, index >::type >::type
get( tuple const &t )
    { return t.value; }

于 2011-09-15T23:18:18.130 に答える
3

C ++のルールでは、通常、要求しているものは許可されていません。

構造体は、既知の型の値のコレクションであり、コンパイル時に指定する必要のある名前でアクセスされます。この最後の部分は、C ++コンパイラがあなたが話している値を知ることができるため、非常に重要です。

Aは、数値tupleによってアクセスされる既知のタイプの値のコレクションです。ただし、数値であるからといって、実行時に定義された数値になるわけではありません。構造体のメンバーの文字列名があるからといって、実行時にそのメンバーを取得できるわけではありません。

の各メンバーtupleは型指定されており、C ++が機能するには、コンパイル時にその種類を知る必要があります。同様に、関数の戻り型はコンパイル時にわかります。パラメータの値に基づいて変更することはできません。タイプ(関数のオーバーロードまたはテンプレート引数の推定)に基づいて別の関数を選択できますが、値(コンパイル時定数でない限り)は実行時にのみ認識されるため、値に基づくことはできません。

あなたが望むことをするために、あなたは何らかの方法でC++型システムを壊さなければならないでしょう。たとえば、理論的にはget、型のないポインタを返す関数を使用できます。または、型安全性の少なくともいくつかのふりが必要な場合は、おそらく、、boost::anyまたはboost::varianttuple型です。しかし、それはあなたができることになる最高のことです。

コンパイル時に型を指定しても(get<Type>)、型の不一致の可能性があるため、それでも十分ではありません。だったらどうしようか?

この概念は、C++のようなコンパイル時の型付き言語では実際には機能しません。

于 2011-09-16T00:53:20.457 に答える
1

それは架空のものではありません。boost::tupleはあなたが説明したように動作します。

boost::tuple<int, float> myTuple = boost::make_tuple(10, 3.1);
int myInt = myTuple.Get<0>();
于 2011-09-15T23:17:51.307 に答える
1

標準ライブラリには、型を明示的に指定する必要がなく、動作std::getする関数テンプレートが含まれています。インデックスをテンプレートパラメータとして使用することで機能します。std::tuplestd::pair

std::tuple<int,std::string,char const*> t(1,"foo","blah");
auto i = std::get<0>(t); // i is int
auto s = std::get<1>(t); // s is std::string
auto p = std::get<2>(t); // p is char const*

戻り値の型はコンパイル時に常に認識されている必要があり、インデックスに依存するため、実行時の引数としてインデックスを使用できない可能性があります。

于 2011-09-15T23:19:05.323 に答える
1

したがって、インデックスをコンパイル時のパラメーターとして渡すとこれが機能することを説明するいくつかの返信が既にあります。ただし、一般的なアイデアについてコメントしたいと思います。

テンプレート化された暗黙の変換演算子を持つプロキシを返すトリックを見たことがあると思います。

template<typename T> operator T()

(ただし、コードでこれをチェックするのが面倒です。誰かが作業を行って実際の例を示してくれる場合は、ここにコメントを残してください。賛成票を投じる可能性があります。)

もちろん、そのようなハッキングの場合と同様に、それだけの価値があるかどうかを自問する必要があります。暗黙の変換は、いつでもつまずく可能性があります。(以前は、それらは悪ではない場合もあると考えていました。しかし、ある日、私の作業コードの最後の暗黙的な変換を削除しなければなりませんでした。これは、バグを見つけるのが非常に困難であり、二度と使用しないことを誓ったためです。
) 、タイプを綴る必要があるという追加の安全性は、シートベルトとして機能できます(ひどく失敗したときにフロントガラスに押しつぶされるのを防ぎます).
最後に、C++11 ではこれが可能です。

auto foo = bar.get<int>(); // available today at a compiler near you

ほら、タイプは一度しか綴られていません。:)

于 2011-09-16T06:50:43.007 に答える
1

MyTuple.Get(0);そのような Get 宣言の戻り値の型は何でしょうか? タプル内の可能なすべての型に対してバリアントを返すことに問題がなければ、それを機能させることができます。

一方、Boost.Tuple と C++0x Tuple はインデックスをテンプレート パラメーターとして受け取ります。間違いの可能性はありません。それらをチェックしてください。

于 2011-09-15T23:17:43.763 に答える
0

あなたは確かにそれを行うことができますが、おそらくそれだけの価値はありません. これを行う 1 つの方法は、可変個引数テンプレート インスタンス メンバーを に変換する静的関数を提供し、関数boost::anyの静的テーブルを用意することです。

template <...> class any_tuple 
{
...
    typedef boost::any (*extract_member)(any_tuple &);
    static extract_member member_extrators[...];

    boost::any Get(int index) { return member_extractors[index](*this); }
};

しかし、その後、初期化とそのすべてについて心配する必要があります。

于 2011-09-16T00:18:17.680 に答える