0

プロジェクトには、静的配列として実装された行列などをカプセル化するクラスがいくつかあります。例:

struct StaticContainer
{
    static const short e[2][4];
};

/// Initialize components of member-array (with external linkage).
const short StaticContainer::e[2][4] = {
    { -1,  0, 0, 1 },
    {  0, -1, 1, 0 }
};

StaticContainer :: eの列から2番目のインデックス(この場合は1〜4)に逆マッピングを提供するメタ関数を実装したいと思います。理想的には、次のようなものです。

template< typename TContainer, short TeX, short TeY >
struct VectorToIndex
{
    enum { value = ??? };
};

最後に、私は合格したいと思います(これが可能であれば):

BOOST_STATIC_ASSERT( 0 == VectorToIndex< StaticContainer, -1, 0 >::value );

これは可能ですか?'e'行列を再帰的に検索する最初の試みは失敗しました。これは、(コンパイル時に)取得しようとするたびに(GCC)次のようになるためです。

error: ‘StaticContainer::e’ cannot appear in a constant-expression

マトリックスの値がコンパイル時に利用できないことを理解しますか?

コメントをいただければ幸いです。マトリックスの初期化/保存方法は自由に変更できます(したがって、コンパイル時の登録メカニズムについて考えていました)。唯一の制約は、コンパイル時にこの逆マッピングを取得することです。

明確化:

  • e-matrixの各列は、空間方向(この場合は2D)を表します。列は明確であることが保証されています。

  • メタ関数から次の結果が得られると思います。

    VectorToIndex< StaticContainer, -1, 0 > --> '0' at compile-time
    VectorToIndex< StaticContainer,  0,-1 > --> '1' at compile-time
    VectorToIndex< StaticContainer,  0, 1 > --> '2' at compile-time
    VectorToIndex< StaticContainer,  1, 0 > --> '3' at compile-time
    

このテンプレートが無効な数値の組み合わせ(つまり、マトリックスの列ではない)でインスタンス化された場合、コンパイルエラーが発生します。

  • 私が現在持っている解決策は、必要なテンプレートインスタンス化を使用してファイルを手動で書き込む単純なプログラムです。これは要件を満たします(結果は正しく、無効なベクトルの場合、対応するテンプレートインスタンスが欠落しているため、コンパイル時エラーが発生します)。ただし、コードベースには「StaticContainer」に似たクラスがたくさんあるので(それらの多くはより大きな行列を持っています)、このプロセスは数千行のコードを生成します:(。
4

2 に答える 2

0

約束通り、ここに解決策があります。可変個引数テンプレートを使用してメタプログラミングライブラリ全体を再発明するのではなく、この機会を利用してブーストmplを試してみたところ、かなり表現力豊かであることがわかりました。これを使用すると、VectorToIndexは次のようになります。

template<typename basis, typename axis>
struct VectorToIndex : 
    boost::mpl::if_<
        boost::mpl::greater<boost::mpl::size<basis>, typename boost::mpl::find<basis, axis>::type::pos>,
        typename boost::mpl::find<basis, axis>::type::pos,
        boost::mpl::empty_base
    >::type
{
};

「axis」が「basis」に存在する場合VectorToIndex<basis, axis>::value、[0、size-of-basis)の範囲のインデックスに等しくなります。それ以外の場合、これはVectorToIndex<basis, axis>::value定義されていないよりも当てはまらないため、これにアクセスすると、コンパイル時エラーまたはSFINAEを介した選択的なインスタンス化が発生する可能性があります。

軸を表すには、以下に示すように、boost :: mpl::vectorを使用する必要があります。

typedef boost::mpl::vector<boost::mpl::int_<1>, boost::mpl::int_<0>, boost::mpl::int_<0> > e1;
typedef boost::mpl::vector<boost::mpl::int_<0>, boost::mpl::int_<1>, boost::mpl::int_<0> > e2;
typedef boost::mpl::vector<boost::mpl::int_<0>, boost::mpl::int_<0>, boost::mpl::int_<1> > e3;

上記の定義を考慮すると、

VectorToIndex<boost::mpl::vector<e1, e2, e3>, e1>::value -> 0
VectorToIndex<boost::mpl::vector<e1, e2, e3>, e2>::value -> 1
VectorToIndex<boost::mpl::vector<e1, e2, e3>, e3>::value -> 2
VectorToIndex<boost::mpl::vector<e1, e2>, e3>::value -> COMPILE-TIME ERROR
于 2012-11-08T00:29:21.017 に答える
0

宣言に不一致があります:

  • typename TContainerテンプレートパラメータがタイプであることを意味します
  • StaticContainer::e値です

一致することはできません。

私が考えることができるいくつかの潜在的な解決策がありますが、最初の質問は明らかにです:逆行列を手動で作成し、assertその正しさを証明するために使用してみませんか?確かにシンプルで、シンプルが美しいです。

于 2012-05-22T16:25:32.677 に答える