Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

Call Traits

Boost , ,

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

Header <boost/call_traits.hpp>

Все содержимое определяется внутри пространства имен.

Класс шаблонов call_traits инкапсулирует метод "best" для передачи параметра некоторого типа T в функцию или из нее и состоит из набора типдефов, определенных в таблице ниже. Цель Call_traits заключается в том, чтобы гарантировать, что такие проблемы, как " ссылки на ссылки", никогда не возникают и что параметры передаются наиболее эффективным образом (см. Примеры). В каждом случае, если ваша существующая практика заключается в использовании типа, определенного слева, то замените его на Call_traits, определенный тип справа.

Обратите внимание, что для компиляторов, которые не поддерживают ни частичную специализацию, ни шаблоны-члены, никакой пользы от использования call_traits не будет: определяемые типы call_traits всегда будут такими же, как существующая практика в этом случае. Кроме того, если компилятор поддерживает только шаблоны-члены, а не частичную специализацию шаблона (например, Visual C++ 6), то Call_traits не может использоваться с типами массивов (хотя он может использоваться для решения проблемы ссылки на ссылку).

Existing practice

call_traits equivalent

Description

Notes

T
(return by value)

call_traits<T>::value_type

Defines a type that represents the "value" of type T. Use this for functions that return by value, or possibly for stored values of type T.

2

T&
(return value)

call_traits<T>::reference

Defines a type that represents a reference to type T. Use for functions that would normally return a T&.

1

const T&
(return value)

call_traits<T>::const_reference

Defines a type that represents a constant reference to type T. Use for functions that would normally return a const T&.

1

const T&
(function parameter)

call_traits<T>::param_type

Defines a type that represents the "best" way to pass a parameter of type T to a function.

1,3

Примечания:

  1. Если T уже является эталонным типом, то call_traits определяется таким образом, чтоссылки на ссылкине встречаются (требуется частичная специализация).
  2. Если T является типом массива, то call_traits определяетvalue_typeкак "постоянный указатель на тип", а не "массив типа" (требует частичной специализации). Обратите внимание, что если вы используете value_type в качестве сохраненного значения, это приведет к хранению постоянного указателя на массив, а не на сам массив. Это может быть или не быть хорошей вещью в зависимости от того, что вам действительно нужно (другими словами, позаботьтесь!).
  3. Если T — малый, встроенный в тип или указатель, тоparam_typeопределяется какT const, а неT const&. Это может улучшить способность компилятора оптимизировать петли в теле функции, если они зависят от пройденного параметра, семантика пройденного параметра в остальном неизменна (требуется частичная специализация).

 

Copy constructibility

Следующая таблица определяет, какие типы call_traits всегда можно скопировать, из каких других типов эти записи, помеченные буквой «?», верны только тогда и только тогда, когда T является копируемым:

 

To:

From:

T

value_type

reference

const_reference

param_type

T

?

?

Y

Y

Y

value_type

?

?

N

N

Y

reference

?

?

Y

Y

Y

const_reference

?

N

N

Y

Y

param_type

?

?

N

N

Y

 

Если T является присваиваемым типом, возможны следующие назначения:

 

To:

From:

T

value_type

reference

const_reference

param_type

T

Y

Y

-

-

-

value_type

Y

Y

-

-

-

reference

Y

Y

-

-

-

const_reference

Y

Y

-

-

-

param_type

Y

Y

-

-

-

 

Examples

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

 

Call_traits type:

Original type T

value_type

reference

const_reference

param_type

Applies to:

myclass

myclass

myclass&

const myclass&

myclass const&

All user defined types.

int

int

int&

const int&

int const

All small built-in types.

int*

int*

int*&

int*const&

int* const

All pointer types.

int&

int&

int&

const int&

int&

All reference types.

const int&

const int&

const int&

const int&

const int&

All constant-references.

int[3]

const int*

int(&)[3]

const int(&)[3]

const int* const

All array types.

const int[3]

const int*

const int(&)[3]

const int(&)[3]

const int* const

All constant-array types.

 

Example 1:

Следующий класс является тривиальным классом, который хранит некоторый тип T по значению (см. файл call_traits_test.cpp), цель состоит в том, чтобы проиллюстрировать, как можно использовать каждый из доступных наборов call_traits:

template <class T>
struct contained
{
   // define our typedefs first, arrays are stored by value
   // so value_type is not the same as result_type:
   typedef typename boost::call_traits<T>::param_type       param_type;
   typedef typename boost::call_traits<T>::reference        reference;
   typedef typename boost::call_traits<T>::const_reference  const_reference;
   typedef T                                                value_type;
   typedef typename boost::call_traits<T>::value_type       result_type;
   // stored value:
   value_type v_;
   
   // constructors:
   contained() {}
   contained(param_type p) : v_(p){}
   // return byval:
   result_type value() { return v_; }
   // return by_ref:
   reference get() { return v_; }
   const_reference const_get()const { return v_; }
   // pass value:
   void call(param_type p){}
};

Example 2 (the reference to reference problem):

Рассмотрим определение std::binder1st:

template <class Operation> 
class binder1st : 
   public unary_function<typename Operation::second_argument_type, typename Operation::result_type> 
{ 
protected: 
   Operation op; 
   typename Operation::first_argument_type value; 
public: 
   binder1st(const Operation& x, const typename Operation::first_argument_type& y); 
   typename Operation::result_type operator()(const typename Operation::second_argument_type& x) const; 
}; 

Теперь рассмотрим, что происходит в относительно распространенном случае, когда функтор принимает свой второй аргумент в качестве ссылки, что подразумевает, что Операция::second_argument_type является эталонным типом, оператор() теперь в конечном итоге будет принимать ссылку на ссылку в качестве аргумента, и это в настоящее время не является законным. Решение здесь состоит в том, чтобы изменить оператор(), чтобы использовать Call_traits:

typename Operation::result_type operator()(typename call_traits<typename Operation::second_argument_type>::param_type x) const;

Теперь в случае, когда Операция::second_argument_type является эталонным типом, аргумент передается в качестве ссылки, и возникает ссылка на ссылку.

Example 3 (the make_pair problem):

Если мы передаем имя массива как один (или оба) аргумента std::make_pair, то дедукция аргумента шаблона выводит переданный параметр как "const ссылка на массив T", это также относится к строковым буквам (которые на самом деле являются буквальными массивами). Следовательно, вместо того, чтобы возвращать пару указателей, он пытается вернуть пару массивов, и поскольку тип массива не является копируемым, код не компилируется. Одно из решений состоит в том, чтобы явно отбрасывать аргументы, чтобы сделать парой указатели, но call_traits обеспечивает лучшее (т.е. автоматическое) решение (и то, которое безопасно работает даже в общем коде, где актерский состав может сделать неправильные вещи):

template <class T1, class T2>
std::pair<
   typename boost::call_traits<T1>::value_type, 
   typename boost::call_traits<T2>::value_type> 
      make_pair(const T1& t1, const T2& t2)
{
   return std::pair<
      typename boost::call_traits<T1>::value_type, 
      typename boost::call_traits<T2>::value_type>(t1, t2);
}

Здесь выведенные типы аргументов будут автоматически деградировать до указателей, если выведенные типы являются массивами, аналогичные ситуации происходят в стандартных связующих и адаптеров: в принципе, в любой функции, что "wraps" временной, чей тип выводится. Обратите внимание, что аргументы функции make_pair не выражены в терминах call_traits: это предотвратило бы дедукцию аргумента шаблона от функционирования.

Example 4 (optimising fill):

Шаблон call_traits будет "оптимизировать" прохождение небольшого встроенного типа в качестве функционального параметра, это в основном имеет эффект, когда параметр используется в корпусе петли. В следующем примере (см. fill_example.cpp) версия std::fill оптимизируется двумя способами: если пройденный тип представляет собой один байт встроенного типа, то для выполнения заполнения используется std::memset, в противном случае используется обычная реализация C++, но с пройденным параметром "optimized" с использованием call_traits:

namespace detail{
template <bool opt>
struct filler
{
   template <typename I, typename T>
   static void do_fill(I first, I last, typename boost::call_traits<T>::param_type val)
   {
      while(first != last)
      {
         *first = val;
         ++first;
      }
   }
};
template <>
struct filler<true>
{
   template <typename I, typename T>
   static void do_fill(I first, I last, T val)
   {
      memset(first, val, last-first);
   }
};
}
template <class I, class T>
inline void fill(I first, I last, const T& val)
{
   enum{ can_opt = boost::is_pointer<I>::value
                   && boost::is_arithmetic<T>::value
                   && (sizeof(T) == 1) };
   typedef detail::filler<can_opt> filler_t;
   filler_t::template do_fill<I,T>(first, last, val);
}

Сноска: причина, по которой это является "оптимальным" для небольших встроенных типов, заключается в том, что с значением, переданным как "T const" вместо "const T&", компилятор может сказать и то, что значение является постоянным и что оно свободно от псевдонимов. С помощью этой информации компилятор может кэшировать пройденное значение в регистре, разворачивать цикл или использовать явно параллельные инструкции: если какая-либо из них поддерживается. Точный пробег, который вы получите от этого, зависит от вашего компилятора - мы действительно можем использовать какое-то точное программное обеспечение для бенчмаркинга.

Обратите внимание, что аргументы функции для заполнения не выражаются в терминах call_traits: это предотвратило бы дедукцию аргумента шаблона от функционирования. Вместо того, чтобы заполнять действия в качестве "тонкой обертки", которая существует для выполнения вычета аргументов шаблона, компилятор оптимизирует вызов, чтобы заполнить все вместе, заменяя его призывом к заполнению <>::do_fill, который использует Call_traits.

Rationale

Следующие примечания предназначены для краткого описания рациональных решений, сделанных в Call_traits.

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

Небольшие встроенные типы (то, что стандарт называет фундаментальными типами [3.9.1]) отличаются от существующей практики только в param_type typedef. В этом случае прохождение "T const" совместимо с существующей практикой, но в некоторых случаях может улучшить производительность (см. Пример 4), в любом случае это никогда не должно быть хуже, чем существующая практика.

Указатели следуют той же рациональности, что и небольшие встроенные типы.

Для типов ссылок рациональное Пример 2 - ссылки на ссылки не допускаются, поэтому члены call_traits должны быть определены так, чтобы эти проблемы не возникали. Существует предложение изменить язык таким образом, чтобы "ссылка на ссылку была ссылкой" (выпуск No 106, представленный Бьярном Страуструпом), call_traits::value_type и call_traits< T>::param_type обеспечивает тот же эффект, что и это предложение, без необходимости изменения языка (другими словами, это обходной путь).

Для типов массивов функция, которая принимает массив в качестве аргумента, деградирует тип массива до типа указателя: это означает, что тип фактического параметра отличается от его заявленного типа, что может вызвать бесконечные проблемы в коде шаблона, который полагается на объявленный тип параметра. Например:

template <class T>
struct A
{
   void foo(T t);
};

В этом случае, если мы инстанцируем A, то объявленный тип параметра, переданного функции-члену foo, является int[2], но это фактический тип const int*, если мы попытаемся использовать тип T в теле функции, то есть сильная вероятность того, что наш код не будет компилироваться:

template <class T>
void A<T>::foo(T t)
{
   T dup(t); // doesn't compile for case that T is an array.
}

Используя call_traits, деградация от массива к указателю явна, а тип параметра такой же, как и заявленный тип:

template <class T>
struct A
{
   void foo(typename call_traits<T>::value_type t);
};
template <class T>
void A<T>::foo(typename call_traits<T>::value_type t)
{
   typename call_traits<T>::value_type dup(t); // OK even if T is an array type.
}

Для value_type (возврат по стоимости) может быть возвращен только указатель, а не копия всего массива, и снова call_traits делает деградацию явной. Элемент value_type полезен всякий раз, когда массив должен быть явно деградирован до указателя - Пример 3 предоставляет тестовый пример (Примечание: специализация массива для call_traits является наименее хорошо понятой из всех специализаций call_traits, если данная семантика вызывает для вас конкретные проблемы или не решает конкретную проблему, связанную с массивом, тогда мне было бы интересно услышать об этом). Большинство людей, вероятно, никогда не будут использовать эту специализацию.


Пересмотрено 01 сентября 2000 года

Авторское право 2000 Стив Клири, Беман Доуз, Говард Хиннант и Джон Мэддок. Использование, модификация и распространение регулируются Лицензией на программное обеспечение Boost версии 1.0. (См. сопроводительный файл LICENSE_1_0.txt или копию по адресу ) http://www.boost.org/LICENSE_1_0.txt .

Статья Call Traits раздела может быть полезна для разработчиков на c++ и boost.




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



:: Главная :: ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-05-19 17:38:11/0.0093791484832764/0