Принятие и lvalue и rvalue ссылки на аргумент шаблона класса - PullRequest
2 голосов
/ 05 апреля 2020

У меня есть следующий класс:

template<typename T>
class Foo {
   // ...
   void frobnicate(const T& arg) {
       // [lots of code here]
       do_the_thing(arg);
       // [lots of code here]
   }

   void frobnicate(T&& arg) {
       // [lots of code here, same as above]
       do_the_thing(std::move(arg));
       // [lots of code here, same as above]
   }
}

Есть ли способ удалить дублирование кода между двумя версиями frobnicate без введения вспомогательных функций post и pre?

В идеале я хотел бы написать что-то вроде:

   void frobnicate(/*what goes here?*/ arg) {
       // [lots of code here]
       if (is_rvalue_reference(arg))
          do_the_thing(std::move(arg));
       else
          do_the_thing(arg);
       // [lots of code here]
   }

Есть ли способ сделать это?

Я думаю, если бы T не было аргументом шаблона класса кроме аргумента шаблона функции, я мог бы, вероятно, использовать умный вывод аргумента шаблона (хотя я и не уверен, как именно я это сделаю), но с вовлеченным классом я не уверен, с чего начать ...

1 Ответ

1 голос
/ 05 апреля 2020

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

template<typename T>
class Foo {
   template <typename X>
   void frobnicate(X&& arg) {
       // [lots of code here]
       do_the_thing(std::forward<X>(arg));
       // [lots of code here]
   }
};

Если вы хотите чтобы ограничить тип, принятый frobnicate как T, вы можете применить static_assert или std::enable_if для frobnicate, например

template<typename T>
class Foo {
   template <typename X>
   void frobnicate(X&& arg) {
       static_assert(std::is_same_v<T, std::decay_t<X>>, "X must be the same type of T");
       // [lots of code here]
       do_the_thing(std::forward<X>(arg));
       // [lots of code here]
   }
};

или

template<typename T>
class Foo {
   template <typename X>
   std::enable_if_t<std::is_same_v<T, std::decay_t<X>>> frobnicate(X&& arg) {
       // [lots of code here]
       do_the_thing(std::forward<X>(arg));
       // [lots of code here]
   }
};
...