Подтвердить что ты не робот

Удалить ссылку в decltype (вернуть T вместо T &, где T & является объявлением)

(Если вы являетесь разработчиком С++ 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 для назначения ему x (он мог бы возвращать char, например).

В С++ 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++ теперь соответствует тому, что я возвращаю ссылку на временную.

Как я могу это исправить? Есть ли что-то вроде remove_reference, которое можно использовать как remove_reference(decltype(foo.bar()))?

Я думал о просто объявлении вспомогательного метода, который принимает T& и возвращает a T, а затем определяет тип возврата doSomething как decltype(helper(foo.bar())). Но должен быть лучший способ, я чувствую это.

4b9b3361

Ответ 1

Чтобы удалить ссылку:

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