2009-10-04 9 views
9

免責事項:質問Inheritance instead of typedefとは全く異なり、私は任意の同様の質問を見つけることができませんでした、これまでのtypedef ++メタプログラミング

私は自宅で(C++テンプレートメタプログラミングと遊ぶのが好きほとんどの場合、私はときどき軽くそれを仕事で紹介しますが、私はプログラムがそれについて学ぶことを気にしなかった人にしか読めるようにしたくありません)。しかし、何かがうまくいかないときは、コンパイラのエラーによってかなり出されました。

問題はもちろん、C++のテンプレートメタプログラミングはテンプレートに基づいているため、深くネストされたテンプレート構造内でコンパイラエラーが発生すると、10行のエラーメッセージ。テキストエディタでメッセージをコピー/ペーストしてから実際に起こっていることを知るまでメッセージをインデントしてエラーを追跡する作業を追加しました。

私が知る限り、問題は主にコンパイラとそれがどのようにtypedefを出力するかにあります(入れ子の深さのような他の問題がありますが、実際はコンパイラの障害ではありません)。今後のC++ 0xについては、バリデーショナルテンプレートやタイプ控除(自動)などのクールな機能が発表されていますが、実際には起動するためのエラーメッセージがより好きです。テンプレートのメタプログラミングを使用するのは辛いことがわかります。もっと多くの人が実際にそれらに入ると、これがどうなるのだろうかと思います。

私はコード内のtypedefのいくつかを置き換え、代わりに継承を使用しています。

typedef partition<AnyType> MyArg; 

struct MyArg2: partition<AnyType> {}; 

これはそれほど多くの文字を入力する必要はなく、これは私の意見ではあまり読みにくくありません。実際には、新しい型が左のマージンの近くに現れることが保証されているので、より判読しやすいかもしれません。

しかし、これには別の問題があります。私は愚かな何もしなかったことを確認するために、私は頻繁にそうように私のテンプレート機能/クラスを書いた:

template <class T> T& get(partition<T>&); 

この方法では、私はそれだけで、適切なオブジェクトに対して呼び出すことができることを確信していました。

特にoperator +などの演算子をオーバーロードする場合、演算子の範囲を絞り込む方法や、intのために呼び出されるリスクを実行する方法が必要な場合。

ただし、これはtypedef'ed型で動作しますが、これはエイリアスだけであるためです。コンパイラが使用する前に、それは必ず1は、単にこのメソッドを呼び出すために使用された「本当の」タイプを知ることができますCRTP

template <class Derived, class T> partition; 

template <class Derived, class T> T& get(partition<Derived,T>&); 

を使用することができ、機能については

...相続では動作しません。公的継承。これは、コンパイラが変換を実行する必要があるため、この特定の関数を呼び出さなければならない可能性が減ることに注意してください。

この問題のもう1つの解決策は、自分のタイプに「タグ」プロパティを追加して、それを互いに区別してからSFINAEに数えることです。

struct partition_tag {}; 

template <class T> struct partition { typedef partition_tag tag; ... }; 

template <class T> 
typename boost::enable_if< 
    boost::same_type< 
    typename T::tag, 
    partition_tag 
    >, 
    T& 
>::type 
get(T&) 
{ 
    ... 
} 

は、それは1つが宣言し、別の場所での関数/メソッドを定義する場合は特に、しかし、いくつかのより多くの入力を必要とする(と私は気にしないならば、私のインターフェイスはかなりすぐにごちゃ混ぜです)。それがクラスに来るとき種類のない変換が実行されませんので、しかし、それは複雑になりますん:

template <class T> 
class MyClass { /* stuff */ }; 

// Use of boost::enable_if 

template <class T, class Enable = void> 
class MyClass { /* empty */ }; 

template <class T> 
class MyClass < 
    T, 
    boost::enable_if< 
    boost::same_type< 
     typename T::tag, 
     partition_tag 
    > 
    > 
> 
{ 
    /* useful stuff here */ 
}; 

// OR use of the static assert 

template <class T> 
class MyClass 
{ 
    BOOST_STATIC_ASSERT((/*this comparison of tags...*/)); 
}; 

私は「enable_if」ということより「静的アサート」を使用する傾向があり、私はそれがはるかだと思います私はしばらくしてから帰ってきます。

基本的に私はまだ私の心を作っていないし、ここで公開されているさまざまな技術の間でまだ実験中です。

typedefsまたは継承を使用していますか? メソッド/関数のスコープを制限したり、与えられた引数のタイプ(およびクラス)を制御するにはどうすればよいですか?

もちろん、可能であればもっと個人的な好みがほしいです。特定の技術を使用する正当な理由がある場合、私はむしろそれについて知っているだろう!

EDIT:

私はstackoverflowのを閲覧し、ちょうど私が完全に忘れていたBoost.MPLからこのperlのを見つけました:

BOOST_MPL_ASSERT_MSG

アイデアは、あなたがマクロ3つの引数を与えることである。

  • チェックする条件
  • メッセージ(C++識別子)は、これは、コードの自己文書化とより良いエラー出力の両方でかなり助けることができる

エラーメッセージ

  • (タプルとして)関係タイプのリストに表示するために使用されます。

  • +0

    Re:なぜ2つのタグがありますか?誰かが早く型を入力し、古いタグをチェックする気にしなかったので。そして2つあった。そして、人々は正しいと思ったものを選んだ。そして私が知っている限り、一度タグがSO上に作成されると、それが空になってもタグは利用可能なタグのリストに表示されます。 –

    +0

    "' 'meta-programming'"は33個のエントリを持ち、 "metaprogramming" "は134個のエントリを持っています。私は以前の方が良いと思うでしょうが、大半の人が... とにかく、33の古い質問をして、それらに再度タグを付けることに関するSOの方針は何ですか? – sbi

    +1

    sbi:私は先に進み、それらをすべて「メタプログラミング」に再タグ付けしました。 – xian

    答えて

    4

    あなたがしようとしているのは、テンプレート引数として渡された型が必要な概念を提供しているかどうかを明示的にチェックすることです。 C++ 0X(そしてそれがC++ 1Xになる主な犯人の1人)から投げ出されたコンセプト機能の不足は、適切なコンセプトチェックを行うのは確かに難しいことです。 90年代以降、言語サポートなしで概念チェックライブラリを作成しようとする試みがいくつか行われてきましたが、基本的に達成されたのは、そうするためには、概念がコア言語の機能になる必要があることを示すことですライブラリのみの機能よりも優れています。

    私はtypedefの代わりに派生し、enable_ifを非常に魅力的にするあなたのアイデアは見つかりません。あなた自身が言っているように、実際のコードは、より良いコンパイラエラーメッセージのためだけにあいまいであることがよくあります。

    私は、静的なアサーションの方がはるかに優れていることがわかりました。実際のコードを変更する必要はなく、アルゴリズムでアサーションチェックを行うのに慣れており、実際のアルゴリズムを理解したい場合は精神的にスキップし、エラーメッセージはより良くなり、Cに引き継がれます。 ++ 1Xの方が良いでしょう。これは、言語に組み込まれたstatic_assert(クラスデザイナーが提供するエラーメッセージを完全に含む)を持つことになります。 (私はBOOST_STATIC_ASSERTが利用可能であれば、内蔵のstatic_assertを単に使用すると思う)

    +0

    私はそれが実際にコードを詰まらせてより良いエラーを得るのは馬鹿だと同意します... –

    +0

    @Matthieu:私はその声明には本当に同意しません。あなたはランタイムコードを乱雑にして、結局。しかし、 'static_assert'は、乱雑さを少なくしてほぼ同じようになるようです。 – sbi

    +0

    はい、それは私が言いたいことです...よく英語でいくつかの問題があります:\ ...私はちょうどenable_ifを使用することは、(static_assertと比較して)本当に冗長な方法であることを意味しました。おそらくこれが可能な唯一の方法であるいくつかのケースがありますが、なぜBoostの人たちがそのような獣を作るのでしょうか? –