Автоматически использовать const-ref по большим параметрам

Когда у меня есть следующий псевдокласс:

template <class T> class tmplClass
{
    void doSomething(T input);
};

Есть ли способ изменить void doSomething(T input) в void doSomething(const T& input) когда sizeof(T) больше, то архитектура системы.

Значит, когда у вас есть tmplClass<char> c; например, использовать void doSomething(T input) и когда у вас есть tmplClass<[another big class with lots of variables]> использование void doSomething(const T& input)

  1. Получу ли я какую-либо оптимизацию от этого?
  2. Есть ли что-нибудь, что я должен сделать, или gcc может сделать это автоматически
  3. Если я должен что-то сделать, что?

2 ответа

Решение

Конечно:

template<typename T, bool=true>
struct eff_arg {
  typedef T type;
};
template<typename T>
struct eff_arg<T, (sizeof(T)>sizeof(int))> {
  typedef T const& type;
};
// C++11 addition

template<typename T>
using EffArg = typename eff_arg<T>::type;

использовать:

template <class T> class tmplClass
{
  // C++11
  void doSomething(EffArg<T> input);
  // C++03
  void doSomething(typename eff_arg<T>::type input);
};

и заменить sizeof(int) с любым типом, который вы хотите использовать в качестве "точки, где вы хотите передать в качестве ссылки, а не по значению".

Обратите внимание, что размер параметра - посредственный способ принять это решение: чрезвычайно маленький класс (даже меньше, чем указатель!) Может иметь глубокую семантику копирования, где большая структура дублируется при дублировании. И часто отрезок не должен быть размером int или указатель, но больше, чем это, потому что косвенное обращение имеет цену.

Идея может заключаться в том, чтобы копировать только объекты, которые не управляют ресурсами и являются достаточно маленькими. std::is_trivially_copyable<T>::value && (sizeof(T) <= 2*sizeof(void*)) может быть вид проверки, которую вы должны сделать перед прохождением T а не T const& когда вам не нужно копировать данные.

Это приводит к следующему:

template<typename T, bool=true>
struct eff_arg {
  typedef T const& type;
};
template<typename T>
struct eff_arg<T,
  std::is_trivially_copyable<T>::value
  && (sizeof(T)<=2*sizeof(void*))
> {
  typedef T type;
};
template<typename T>
using EffArg = typename eff_arg<T>::type;

Да легко

#include <type_traits>

template <typename T> struct Foo
{
    void do_something(typename std::conditional<(sizeof(T) > sizeof(void *)),
                                                 T const &, T>::type x)
    {
        // ... use "x"
    }

    // ...
};

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

Как подсказывает @Yakk, было бы неплохо добавить std::is_trivially_copyable<T>::value к условию, чтобы избежать случайного копирования чего-то, что дорого скопировать или что может бросить.

Другие вопросы по тегам