63

(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>代入するためにメソッドが int を返す必要がないため、コンパイル エラーが発生します(たとえば、返される可能性があります)。xchar

C++0x/11 では、テンプレート メソッドの戻り値の型を推測するために使用できるautoandがあります。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);

今私の質問に:

MyClassbar()が を返すように定義されている場合int&、 の戻り値の型doSomething(object)int&=になりdecltype(foo.bar())ます。これは問題です。G++ が準拠するようになったため、一時的な参照を返しているからです。

どうすればこれを修正できますか? remove_referenceのように使えるものはありremove_reference(decltype(foo.bar()))ますか?

T&a を受け取って aを返すヘルパー メソッドを宣言し、Tの戻り値の型doSomethingを be に定義することだけを考えましdecltype(helper(foo.bar()))た。しかし、もっと良い方法があるはずです、私はそれを感じています。

4

1 に答える 1

63

参照を削除するには:

#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
}
于 2012-11-02T20:14:56.217 に答える