web-dev-qa-db-ja.com

decltypeの参照を削除します(T&の代わりにTを返します。T&はdecltypeです)。

(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には、autodecltypeがあり、これらを使用してテンプレートメソッドの戻り値の型を推定できます。

_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()))として定義するヘルパーメソッドを宣言することを考えました。しかし、もっと良い方法があるはずだと感じています。

52
leemes

参照を削除するには:

#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
}
52
GManNickG