Правильный способ использования Decktype в качестве типа возврата следа

StackOverflow https://stackoverflow.com/questions/5802266

Вопрос

Я очень часто вижу пример этой формы:

template <typename T, typename U>
auto add(T&& t, U&& u) -> decltype(std::forward<T>(t) + std::forward<U>(u))
{
    return std::forward<T>(t) + std::forward<U>(u);
}  

Но я смею сказать, что это лучше правильно:

template <typename T, typename U>
auto add(T&& t, U&& u) -> decltype(t + u)//no forwarding here
{
    return std::forward<T>(t) + std::forward<U>(u);
}

Почему? В первую очередь, Decltype в этом примере должен только вывести тип возврата, поэтому (t + U) - это тип возврата, а не (std :: forward (t) + std :: forward (u)), второй код, сгенерированный двумя Ver Identicall, и Third Decktype (U + T) более прямой и точно выражает то, что намерения программиста не выявляют «кишки» реализации.

Что вы думаете по этому вопросу?

Это было полезно?

Решение

В общем, я не могу придумать о разумном случае использования, когда будет разница, но я думаю, что вы можете найти какой-то случай, когда операция имеет разные реализации для RVALUE-ссылок и RVALUE, и языковые правила не определяют, что возврат Тип различных перегрузков должен быть одинаковым (даже если здравый смысл будет диктовать это).

Таким образом, в общем случае не будет никакой разницы, и в случае, когда существуют различия, ну, эти случаи нуждаются в дополнительной заботе и внимании к гораздо худшим проблемам, чем сам шаблон ...

// sick corner case:
struct type {};
int operator+( type&& lhs, type&& rhs );
double operator+( type const & lhs, type const & rhs );

Я могу подумать в ситуациях, когда вы хотели бы предложить различные перегрузки для запросов RVALUE (рассмотрите некоторую реализацию списка, который предлагает operator+ В качестве объединения, тогда перегрузка с ссылками на RVALUE может избежать стоимости копирования, просто искажая указатели и оставляя аргумент, перечисляет пустые), но это было бы совершенно запутанно, если тип результата будет зависеть от L/RValue-tessess аргументов.

Другие советы

Первая версия более правильная, потому что она точно соответствует тому, что будет возвращать корпус функции. Как уже отмечалось, просто нет никакой гарантии, что

decltype(std::forward<T>(t) + std::forward<U>(u))

будет тот же тип, что и

decltype(t + u)

Возможно, это довольно угловой корпус, но «правильный» способ использовать Std :: Forward.

В пределах decltype(t + u), переменные t а также u Уже больше нет ссылок на RVALUE, они будут рассматриваться как простые ссылки на LVALU std::forwardАнкет (По крайней мере, вот как я это понимаю. Хотя может быть не так.)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top