Я хочу написать функцию identity
который отлично передает свой аргумент без какой-либо копии. Я бы написал что-то вроде этого
template< typename V >
inline V&& identity( V&& v )
{
return std::forward< V >( v );
}
Но правильно ли это? Всегда ли он возвращает правильный тип? Это просто вперед v
независимо, если это lvalue / lvalue ссылка / временная?
Вы можете использовать пакет параметров в качестве защиты, так что никто не может на самом деле заставить тип, который отличается от того, который был бы выведен в противном случае.
Как минимальный рабочий пример:
#include <type_traits>
#include <utility>
template<typename..., typename V>
constexpr V&& identity(V&& v) {
return std::forward<V>(v);
}
int main() {
static_assert(std::is_same<decltype(identity(42)), int&&>::value, "!");
static_assert(std::is_same<decltype(identity<int>(42)), int&&>::value, "!");
static_assert(std::is_same<decltype(identity<float>(42)), int&&>::value, "!");
// here is the example mentioned by @Jarod42 in the comments to the question
static_assert(std::is_same<decltype(identity<const int &>(42)), int&&>::value, "!");
}
Таким образом, тип возвращаемого значения зависит от фактического типа v
параметр, и вы не можете сила копия в любом случае.
Как упоминалось в комментариях @bolov, синтаксис может быстро стать неясным.
В любом случае, как подсказывает @ Jarod42, нужно быть более ясным в том, что мы делаем.
В качестве примера:
template <typename... EmptyPack, typename V, typename = std::enable_if_t<sizeof...(EmptyPack) == 0>>
Как альтернатива:
template <typename... EmptyPack, typename V, std::enable_if_t<sizeof...(EmptyPack) == 0>* = nullptr>
Или даже:
template <typename... EmptyPack, typename V>
constexpr
std::enable_if_t<sizeof...(EmptyPack) == 0, V&&>
identity(V&& v) {
return std::forward<V>(v);
}
Подберите предпочтительный вариант и используйте его, все они должны быть действительными в этом случае.
Других решений пока нет …