Как правильно использовать ссылки с вариационными шаблонами - PullRequest
13 голосов
/ 11 апреля 2010

У меня есть что-то вроде следующего кода:

   template<typename T1, typename T2, typename T3, typename T4>
   void inc(T1& t1, T2& t2, T3& t3, T4& t4) { ++t1; ++t2; ++t3; ++t4; }

   template<typename T1, typename T2, typename T3>
   void inc(T1& t1, T2& t2, T3& t3) { ++t1; ++t2; ++t3; }

   template<typename T1, typename T2>
   void inc(T1& t1, T2& t2) { ++t1; ++t2; }

   template<typename T1>
   void inc(T1& t1) { ++t1; }

Я бы хотел переопределить его, используя предложенные вариационные шаблоны из будущего стандарта. Однако все примеры, которые я видел до сих пор в Интернете, кажутся похожими на printf, разница здесь, похоже, заключается в использовании ссылок. Я придумал следующее:

inline void inc() { }

template<typename T>
inline void inc(T&& t) { ++t; }

template<typename T,typename ... Args>
inline void inc(T&& t, Args&& ... args) { ++t; inc(args...); }

То, что я хотел бы знать, это:

  • Должен ли я использовать r-значения вместо ссылок?

  • Возможные подсказки или подсказки относительно того, как правильно выполнить то, что я хочу.

  • Какие гарантии предоставляет новый предлагаемый стандарт в отношении вопроса о рекурсивных вызовах функций, есть ли какой-либо признак того, что приведенная выше версия с переменным числом аргументов будет столь же оптимальной, как и оригинал? (Должен ли я добавить inline или что-то в этом роде?)

Ответы [ 3 ]

12 голосов
/ 11 апреля 2010

Я бы не стал использовать здесь ссылки на rvalue, потому что это позволит вам привязать к значениям rvalue, которые могут разрешать такой бессмысленный код как:

inc(1);

Итак, я бы придерживался регулярных ссылок:

template<typename T>
void inc(T& t) { ++t; }

template<typename T,typename ... Args>
void inc(T& t, Args& ... args) { ++t; inc(args...); }
2 голосов
/ 11 апреля 2010

Должен ли я использовать r-значения вместо ссылок?

Вы имеете в виду rvalue ссылки? Нет, я не вижу причин для этого.

Возможные подсказки или подсказки относительно того, как правильно выполнить то, что я хочу.

Ты уже там. Ваш код должен делать то, что вы хотите.

Какие гарантии предоставляет новый предложенный стандарт в отношении рекурсивных вызовов функций, есть ли какой-либо признак того, что приведенная выше версия с переменным числом аргументов будет столь же оптимальной, как и оригинал? (Должен ли я добавить inline или что-то в этом роде?)

Стандарт C ++ не гарантирует никакого встраивания. Вы можете проверить, что генерирует компилятор. Если вы хотите, чтобы все было встроено - включая самый высокий inc-вызов - вы могли бы поместить inline для обеих функций как request . Если вы хотите что-то наподобие вашего не вариадического шаблона, вы можете обернуть его так:

inline void inc_impl() {}

template<typename T, typename...U>
inline void inc_impl(T& t, U&...u) { ++t; inc_impl(u...); }

template<typename...T>
void inc(T&...t) { inc_impl(t...); }

Теперь inc не является встроенным, в то время как каждая из его реализаций, вероятно, не будет содержать реальных вызовов функций, когда будет выполнено встраивание вызовов inc_impl - но опять же, нет гарантии.

1 голос
/ 11 апреля 2010

Какие гарантии предоставляет новый предлагаемый стандарт в отношении рекурсивных вызовов функций, есть ли какой-либо признак того, что приведенная выше вариационная версия будет столь же оптимальной, как и оригинал? (Должен ли я добавить inline или что-то в этом роде?)

Стандарт не гарантирует, что будет выполнена оптимизация, он только определяет поведение и результат. Будет ли в функции встроена проблема реализации.

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

Наконец, g ++ - 4.5 полностью встроил все inc функции на -O2. Не знаю, хочешь ли ты этого.

...