web-dev-qa-db-ja.com

オブジェクトなしでメンバー関数の戻り値の型を取得する

変更できないクラスがいくつかあります。それぞれに、コピーコンストラクター、少なくとも1つの他のコンストラクター、および何らかの値を返す関数foo()があります。これらの各クラスから派生でき、foo()の戻り値の型と同じ型のデータメンバーを持つクラステンプレートを作成したいと思います(用語の一部が間違っている場合は申し訳ありません)。 。

つまり、クラステンプレートが欲しいのですが

template<typename T> class C : public T
{
  footype fooresult;
};

ここで、footypeT::foo()の戻り値の型です。

基本クラスがすべて、たとえばデフォルトのコンストラクターを持っている場合、私は

decltype(T().foo()) fooresult;

(GCCのC++ 0x機能を使用)ただし、コピーコンストラクターを除いて、クラスには共通の特定のコンストラクターはありません。

GCCもdecltype(this->foo())を許可していませんが、これがC++ 0x標準に追加される可能性があるようです-誰かがそれがどれほど可能性があるか知っていますか?

decltype(foo())またはdecltype(T::foo())に沿って何かを行うことは可能であると思いますが、それらは機能していないようです。GCCはcannot call member function 'int A::foo()' without objectの形式のエラーを出します。

もちろん、追加のテンプレートパラメータfootype、またはタイプTの非クラスパラメータを使用することもできますが、これを回避する方法はありますか?

39
James

それは必要ありません-decltypeはその引数を評価しないので、nullptrを呼び出すだけでよいことを覚えておいてください。

decltype(((T*)nullptr)->foo()) footype;
60
Puppy

別の選択肢は次のとおりです。

#include <utility>

template<typename T> class C : public T
{
   decltype(std::declval<T>().foo()) footype;
};

declvalT&&を返します。または、fooが右辺値参照修飾子でオーバーロードされている可能性があり、fooの左辺値オーバーロードを確実に取得したい場合:

   decltype(std::declval<T&>().foo()) footype;

この例では、declvalT&を返します。

((T*)nullptr)->ソリューションと同様に、std::declvalはタイプTに要件を課しません。

42
Howard Hinnant