Удалить ссылку в decltype (вернуть T вместо T & amp; где T & amp; является 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> тоже приводит к ошибке компиляции, потому что метод не требует возврата int для назначения x потом (может вернуться 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 ++ соответствует возврат ссылки на временный.

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

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

45

Решение

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

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

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]