(C++ 11プロの場合は、太字の段落にスキップしてください。)
型がテンプレートパラメータである渡されたオブジェクトの結果を呼び出して返すテンプレートメソッドを記述したいとします。
_template<ReturnType, T>
ReturnType doSomething(const T & foo) {
return foo.bar(); // EDIT: Might also be an expression introducing a temp val
}
_
したがって、T
には、次のような呼び出しで使用するために、メソッドReturnType T::bar() const
が必要です。
_struct MyClass {
...
int bar() const;
...
};
...
MyClass object;
int x = doSomething<int, MyClass>(object);
_
型推論のおかげでMyClass
を記述する必要はなく、呼び出しは次のようになります。
_int x = doSomething<int>(object);
_
ただし、_<int>
_も省略すると、コンパイルエラーが発生します。これは、後でx
に割り当てるためにメソッドがintを返す必要がないためです(たとえば、char
を返す可能性があります)。
C++ 0x/11には、auto
とdecltype
があり、これらを使用してテンプレートメソッドの戻り値の型を推定できます。
_template<T>
auto doSomething(const T & foo) -> decltype(foo.bar()) {
return foo.bar(); // EDIT: Might also be an expression introducing a temp val
}
_
コンパイラーはfoo.bar()
のタイプを検出し、これを戻り値のタイプとして使用します。具体的なクラスMyClass
を使用すると、これはint
になり、以下で十分です。
_int x = doSomething(object);
_
今私の質問へ:
MyClassがbar()
を_int&
_を返すものとして定義している場合、doSomething(object)
の戻り値の型も_int&
_ = decltype(foo.bar())
になります。これは問題です、なぜならG ++は今私がtemporaryへの参照を返すことに準拠しているからです。
どうすれば修正できますか? remove_reference(decltype(foo.bar()))
のように使用できる_remove_reference
_のようなものはありますか?
_T&
_を使用してT
を返し、doSomething
の戻り値の型をdecltype(helper(foo.bar()))
として定義するヘルパーメソッドを宣言することを考えました。しかし、もっと良い方法があるはずだと感じています。
参照を削除するには:
#include <type_traits>
static_assert(std::is_same<int, std::remove_reference<int&>::type>::value, "wat");
あなたの場合:
template <typename T>
auto doSomething(const T& foo)
-> typename std::remove_reference<decltype(foo.bar())>::type
{
return foo.bar();
}
明確にするために、リファレンスを返すように書かれていても問題ないことに注意してください。
#include <type_traits>
struct f
{
int& bar() const
{
static int i = 0;
return i;
}
};
template <typename T>
auto doSomething(const T& foo)
-> decltype(foo.bar())
{
return foo.bar();
}
int main()
{
f x;
return doSomething(x);
}
返された参照は、エラーなしで単純に渡すことができます。コメント内のあなたの例は、それが重要かつ有用になるところです:
template <typename T>
auto doSomething(const T& foo)
-> decltype(foo.bar())
{
return foo.bar() + 1; // oops
}