「なぜ物事はそうなっているのか」という質問は、通常は最善ではないことは承知していますが、SO には標準的な委員会の議論に同調している人がたくさんいるので、この質問には事実に基づいた回答が得られることを願っています。答えが何なのか、本当に知りたいのです。
基本的に、 のテンプレート シグネチャを初めて見たとき、何が起こっているのか理解するのに長い時間がかかりましたstd::result_of
。これは、これまで見たことのないテンプレート パラメータのまったく新しい構造だと思ったからです。
template< class F, class... ArgTypes >
class result_of<F(ArgTypes...)>;
しばらく考えてみて、これが実際に何なのかが分かりました。F(ArgTypes...)
関数型ですが、ない結果の型が評価される関数の型(つまり):引数F
を取り、ArgTypes...
戻るタイプF
。
これは...奇妙ではないですか? ちょっとハックっぽいですか? 委員会が、たとえば次のような代替案を議論したことがあるかどうか、誰か知っていますか?
template< class F, class... ArgTypes >
class result_of<F, ArgTypes...>;
?
2 番目の構成が最初の構成ほど簡単に使用できない状況がある可能性はあると思いますが、それはどのような状況でしょうか?
これについて判断を下そうとしているわけではありませんが、初めて見たとき、本当に混乱したので、何か良い理由があるのかどうか気になっています。答えの一部は単に「Boost がそうしたから」ということかもしれないとわかっていますが、それでも残りの (事実上の) 疑問は残ります...
Boost が型情報をエンコードするために他の方法ではなくこの構文を選択する技術的な理由はありますか?
std::result_of
いずれにせよかなり簡単に実装できることを考えると、これを標準化することがどれほど適切であるかについて、C++11 委員会で議論はありましたかdecltype
?
ベストアンサー1
関数型をパラメータとして持つことで、C++03 でも制限のない「可変長」クラス テンプレートを持つことができます。考えてみてください。C++03 には可変長テンプレートがありませんでした。また、関数テンプレートのようにクラス テンプレートを「オーバーロード」することはできません。では、関数に異なる数の「引数」を許可することは、他にどのような方法で可能になるのでしょうか。
関数型を使用すると、異なる数のパラメータに対して任意の数の部分的な特殊化を追加できます。
template<class Fty>
struct result_of;
template<class F>
struct result_of<F()>{ /*...*/ };
template<class F, class A0>
struct result_of<F(A0)>{ /*...*/ };
template<class F, class A0, class A1>
struct result_of<F(A0, A1)>{ /*...*/ };
// ...
C++03 でこれを行う唯一の他の方法は、デフォルトのテンプレート引数と、すべてのケースに対して部分的に特殊化することです。欠点は、関数呼び出しのように見えなくなり、result_of
内部で使用するあらゆる種類のラッパーをそのまま渡すことができないことですSig
。
さて、関数型の方法には 1 つの欠点があります - 「パラメーター」に対して通常の変換もすべて実行されることです: R(Args...)
->R(*)(Args...)
そしてさらに重要なのはT[N]
->T*
最上位レベルの cv 修飾子が破棄されることです ( §8.3.5/5
):
struct X{
bool operator()(int (&&arr)[3]);
long operator()(void*);
};
static_assert(std::is_same<std::result_of<X(int[3])>::type, bool>(), "/cry");
実際の例。出力:
エラー: 静的アサーションに失敗しました: /cry
他の問題は、トップレベルの cv 修飾子が破棄されることです。
struct Y{};
struct X{
bool operator()(Y const&);
long operator()(Y&&);
};
Y const f();
static_assert(std::is_same<std::result_of<X(Y const)>::type, bool>(), "/cry");
実際の例。出力:
エラー: 静的アサーションに失敗しました: /cry