20

通常、「なぜそうなのか」という質問は最善ではないことを理解していますが、標準委員会の議論に同調している 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がそうしたから」かもしれないことは理解していますが、それでも残りの(事実上の)質問は残っています...

  • ブーストがこの構文を選択して、代替ではなく型情報をエンコードする技術的な理由はありますか?

  • とにかくかなり簡単にstd::result_of実装できることを考えると、これを標準化することがどれほど適切であるかについて、C++11委員会による議論はありましたか?decltype

4

4 に答える 4

18

パラメータとして関数型を使用すると、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*§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-qualifiers が破棄されることです:

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

于 2013-03-19T01:04:37.743 に答える
9

関数型表記を(ab)使用して、それぞれのファンクター呼び出しがどのように見えるかを模倣できるという考えを誰かが得ただけだと思います。したがって、技術的な理由はなく、美的な理由だけです。

// the result type of a call to (an object of) type F,
// passing (objects of) types A, B, and C as parameters.
result_of<F(A, B, C)>::type
于 2013-03-18T21:12:17.967 に答える
4

result_ofdecltype が言語に追加される前に出てきた TR1 の一部でした。しかし、それはdecltype念頭に置いて設計されているため、実装result_ofを使用するように変更するのdecltypeは簡単です。はい、ハックですが、機能します。

于 2013-03-18T21:09:10.800 に答える
2

(これはJohannesD の回答とそれに関するJesse Good のコメントを拡張しますが、これはコメントに収まりません。これではなく、他の回答に賛成票を投じてください。)

N1454 構文と例から:

の動作の定義result_ofは簡単です。これらの型の型F, T1, T2, ...TNと左辺値f, t1, t2, ...tNがそれぞれ与えられると、型式

result_of<F(T1, T2, ..., TN)>::type

式の型に評価されますf(t1, t2, ..., tN)

これは型システムを悪用しているのではなく、美しくエレガントです!

于 2013-03-19T12:29:30.873 に答える