免責事項:質問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のを見つけました:
アイデアは、あなたがマクロ3つの引数を与えることである。
- チェックする条件
- メッセージ(C++識別子)は、これは、コードの自己文書化とより良いエラー出力の両方でかなり助けることができる
エラーメッセージ
Re:なぜ2つのタグがありますか?誰かが早く型を入力し、古いタグをチェックする気にしなかったので。そして2つあった。そして、人々は正しいと思ったものを選んだ。そして私が知っている限り、一度タグがSO上に作成されると、それが空になってもタグは利用可能なタグのリストに表示されます。 –
"' 'meta-programming'"は33個のエントリを持ち、 "metaprogramming" "は134個のエントリを持っています。私は以前の方が良いと思うでしょうが、大半の人が...とにかく、33の古い質問をして、それらに再度タグを付けることに関するSOの方針は何ですか? –
sbi
sbi:私は先に進み、それらをすべて「メタプログラミング」に再タグ付けしました。 – xian