Посмотрите на этот гипотетический заголовочный файл:
template <class T>
class HungryHippo {
public:
void ingest(const T& object);
private:
...
}
Теперь для HungryHippo<string>
имеет смысл, что вы хотели бы ingest
ссылки на строки — копирование строки может быть очень дорогим! Но для HungryHippo<int>
это делает намного меньше смысла. Проходя int
напрямую может быть очень дешевым (большинство компиляторов делают это в реестре), но передавая ссылку на int
это лишний ненужный уровень косвенности. Это все относится и к возвращаемым значениям.
Есть ли способ предложить компилятору «эй, я не собираюсь изменять аргумент, поэтому вы решить, передать ли по значению или по ссылке, в зависимости от того, что, по вашему мнению, лучше «?
Некоторые вещи, которые могут быть актуальны:
template <class T, bool PassByValue> class HungryHippo
а затем специализируется на PassByValue
, Если бы я хотел стать по-настоящему модным, я мог бы даже сделать вывод PassByValue
основанный на sizeof(T)
а также std::is_trivially_copyable<T>
, В любом случае, это большая дополнительная работа, когда реализации будут выглядеть примерно одинаково, и я подозреваю, что компилятор может гораздо лучше решить, передавать ли его по значению, чем я.ingest
довольно сложный и не стоит встраивать.inline
по умолчанию. boost::call_traits
Заголовок имеет дело именно с этим вопросом. Проверьте это Вот.
В частности, call_traits<T>::param_type
Опция включает в себя следующее описание:
Если
T
небольшой встроенный тип или указатель, тоparam_type
определено
какT const
, вместоT const&
, Это может улучшить способность
компилятор для оптимизации циклов в теле функции, если они зависят
по переданному параметру семантика переданного параметра
в остальном без изменений (требуется частичная специализация).
В вашем случае вы могли бы определить ingest
следующее:
template <class T>
class HungryHippo {
public:
void ingest(call_traits<T>::param_type object);
// "object" will be passed-by-value for small
// built-in types, but passed as a const reference
// otherwise
private:
...
};
Будет ли это на самом деле иметь большое значение в вашей реальной комбинации кода / компилятора, я не уверен. Как всегда, вам нужно выполнить некоторые реальные тесты и посмотреть, что произойдет …
В то время как уловки, такие как повышение упоминалось call_traits<T>
делать то, что они утверждают, что в этом случае, я думаю, вы предполагаете, что компилятор еще не делает эту оптимизацию в наиболее важных случаях. В конце концов, это тривиально. Если вы принимаете const T&
а также sizeof(T) <= sizeof(void*)
инварианты, навязанные C ++ ссылочной семантикой, позволяют компилятору просто подставлять значение по всему телу функции, если это выигрыш. Если это не так, ваши наихудшие издержки — разыменование указателя на аргумент в прологе функции.