2

Рассмотрим следующий шаблон функции:Автоматическая оценка стратегии Выбор в C++

template<typename T> void Foo(T) 
{ 
    // ... 
} 

Pass по значению семантики имеют смысл, если T случается целочисленный тип, или, по крайней мере, тип, который дешев, чтобы скопировать. С другой стороны, использование семантики pass-by- [const] -reference имеет смысл, если T оказывается дорогостоящим типом для копирования.

Предположим на секунду, что вы пишете библиотеку. В идеале, как разработчик библиотеки, ваша задача - предоставить вашим потребителям чистый API, который будет как можно более общим и эффективным. Как тогда вы предоставляете общий интерфейс, который подходит для обоих типов стратегий передачи аргументов?


Вот моя первая попытка получения этой работы:

#include <boost/type_traits.hpp> 

template<typename T> struct DefaultCondition 
{ 
    enum {value = boost::is_integral<T>::value /* && <other trait(s)> */}; 
}; 

template< typename T, class Condition = DefaultCondition<T> > class Select 
{ 
    template<bool PassByValue = Condition::value, class Dummy = void> struct Resolve 
    { 
    typedef T type; 
    }; 

    template<class Dummy> struct Resolve<false, Dummy> 
    { 
    typedef const T& type; 
    }; 

    public: typedef typename Resolve<>::type type; 
}; 

Типичное использование:

template<typename T> class EnterpriseyObject 
{ 
    typedef typename Select<T>::type type; 

    public: explicit EnterpriseyObject(type) 
    { 
    // ... 
    } 
}; 

struct CustomType {}; 

void Usage() 
{ 
    EnterpriseyObject<int>(0); // Pass-by-value. 
    (EnterpriseyObject<CustomType>(CustomType())); // Pass-by-const-reference. 
} 

Это, конечно, косвенно нарушает неявный аргумент шаблона вычет неклассовых шаблоны:

template<typename T> void Foo(typename Select<T>::type) 
{ 
    // ... 
} 

void Usage() 
{ 
    Foo(0);  // Incomplete. 
    Foo<int>(0); // Fine. 
} 

Это может быть «фиксированной» с Boost.Typeof библиотекой и макро, а-ля WinAPI:

#define Foo(Arg) ::Foo<BOOST_TYPEOF((Arg))>((Arg)) 

Хотя это всего лишь квази-портативный хак.

Как вы можете видеть, мой общий подход не является действительно удовлетворительным для всех случаев.


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

  1. ли вам, или вы использовали этот тип оптимизации * в прошлом?
  2. Имеет ли библиотека Boost (или любая другая общественная библиотека) аналогичную функциональность?
  3. Если ответ на # 1 или # 2 является «да» - как обрабатывается случай неклассического шаблона?
  4. Есть ли явные подводные камни, которые я не вижу с чем-то подобным?
  5. Наконец, это даже разумная вещь?

* Не профилированный. ;)

+1

собирался упомянуть http://www.boost.org/doc/libs/1_43_0/doc/html/ref.html – 5ound

+0

@ 5ound: Также полезно, спасибо! – chrosph

ответ

2
  1. Да. Все время. Я использую его сам.
  2. Да, используйте Boost.Utility's Call Traits :)

    Usage бы ...

    template <typename T> 
    void foo(boost::call_traits<T>::param_type param) 
    { 
        // Use param 
    } 
    
  3. Насколько я знаю, передаются по значению шаблонов неклассовых, если это не быстрее нет. Благодаря частичной специализации шаблона, его можно настроить относительно легко.

  4. Прошу прощения, я действительно не читал, что вы делали, это было похоже на то, что я провел несколько месяцев назад. Поэтому я не могу ответить на этот вопрос. Моя рекомендация - просто прочитать Boost.Utility.

  5. Конечно!

+0

Отлично. Должно было выглядеть сложнее перед публикацией. Спасибо! ;) – chrosph

Смежные вопросы