Какие другие полезные приведения могут быть использованы в C ++ - PullRequest
14 голосов
/ 14 мая 2009

C ++ поставляется с четырьмя встроенными приведениями.

  1. static_cast
  2. dynamic_cast
  3. const_cast
  4. reinterpret_cast

Не означает, что нахмурившийся C (style*)cast.

Дополнительно boost поставляет lexical_cast , есть ли другие полезные приведения, которые вы используете или хотели бы существовать?

Ответы [ 10 ]

10 голосов
/ 14 мая 2009

Мой любимый и самый любимый актерский состав - implicit_cast. Это только успешно, если типы могут быть неявно преобразованы.

Полезно для преобразования из некоторого типа в void* или из некоторого производного класса в базу (если вы хотите выбрать конкретный экземпляр перегруженной функции или конструктора) или для безопасного добавления const-квалификаций и любого другого сценария, в котором вы на самом деле просто необходимы неявные преобразования, и даже static_cast слишком мощно.

Также прочитайте Как C ++ выбирает, какую перегрузку вызывать .

boost/implicit_cast.hpp. Вы также можете добавить это в свою коллекцию кода, если хотите

template<typename T> struct identity { typedef T type; };
template<typename Dst> Dst implicit_cast(typename identity<Dst>::type t)
{ return t; }
9 голосов
/ 14 мая 2009

Существует также приведение в стиле функции , которое выглядит как вызов функции или конструктора. Это разрешает вызов конструктора для классов и (в более общем плане) приведение в стиле C для всех других типов.

Примеры:

int x = int(1.0);       // equals `(int)1.0`
string s = string("x"); // equals call to constructor

Вызов в конструктор может также быть выполнен с использованием явного приведения (кроме приведения типа C, который также будет работать):

string s = static_cast<string>("x"); // is the same as above!
8 голосов
/ 14 мая 2009

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

class Person {
   public:
      Person( const std::string & name );
   ...
};

Конструктор Person выполняет преобразование из строки -> Person:

Person p = Person( "fred" );

и будет использоваться компилятором, когда нужно переписать строку с человеком:

void PrintPerson( const Person & p ) {
   ...
}

теперь компилятор может преобразовать строку в Person:

string name = "fred";
PrintPerson( name );

но обратите внимание, что он не может сделать это:

PrintPerson( "fred" );

, поскольку это потребует компилятора для построения цепочки преобразований.

Редактировать: Я разместил дополнительный вопрос по теме конверсий - см. Неявные преобразования C ++ .

4 голосов
/ 14 мая 2009

Одно действительно полезное усиление - оператор (функция действительно) numeric_cast (номер);

Это проверяет, что число, которое вы произносите, находится в диапазоне для типа назначения.

например

long long big_number = ....

int num = numeric_cast<int>(big_number);  // throws an exception is big_number is too big

http://www.boost.org/doc/libs/1_39_0/libs/numeric/conversion/doc/html/boost_numericconversion/improved_numeric_cast__.html

4 голосов
/ 14 мая 2009

Если вы используете shared_ptr, вы можете использовать приведение указателя наддува (boost :: static_pointer_cast, ...). Их также можно использовать для стандартных указателей.

3 голосов
/ 14 мая 2009

Существует также ужасный union_cast .

Это плохо, потому что, строго говоря, это UB, но если вы знаете, что делаете, это может быть полезно для преобразования указателей на функции-члены в void* и обратно, не все компиляторы позволяют делать это с reinterpret_cast.

Но все же этого лучше избегать ..

2 голосов
/ 25 июля 2013

memcpy_cast - строго безопасная и переносимая альтернатива стандартному стандарту типа штамповки :

#include <cstring>

template<typename To, typename From>
inline To memcpy_cast(From x)
{
    // Constraints on types from STLSoft's union_cast:
    //  (1) Sizes must be the same.
    //  (2) Both must be of POD type.
    //  (3) There must be either a change of const/volatile,
    //                        or a change of type, but not both.
    //  (4) Both must be non-pointers, or must point to POD types.
    // 
    // Here checking only (1):
    STATIC_ASSERT(sizeof (To) == sizeof (From));

    To ret;
    std::memcpy(&ret, &x, sizeof ret);
    return ret;
}

(где STATIC_ASSERT - некоторый макрос утверждения времени компиляции (или C ++ 11 static_assert), а ограничения получены из union_cast.hpp STLSoft ).

Затем вы можете попробовать такие вещи, как

uint32_t u = 0x1234ABCD;
//float f = *(float*)&u; // unsafe
float f = memcpy_cast<float>(u); // safe

(Вот еще одна реализация: memcpy_cast.hpp dbg .)

(Редактировать: также, Boost.SIMD имеет bitwise_cast, который внутренне использует memcpy_cast.)

2 голосов
/ 14 мая 2009

ACE имеет truncate_cast . Это в основном полезно для оптимизации кода, подобного следующему:

foo_t bar = ...;
short baz;

if (bar > SHORT_MAX)
  baz = SHORT_MAX;
else
  baz = static_cast<short> (bar);

Это можно заменить на:

foo_t bar = ...;
short baz = ACE_Utils::truncate_cast<short> (bar);

В зависимости от базового типа foo_t , truncate_cast полностью оптимизирует оператор if () , а также обращается к диагностике компилятора, полученной в результате сравнения подписанного и неподписанные типы. Выбор того, какой путь сделать, выполняется во время компиляции с помощью шаблонной метапрограммы.

В идеале не нужно такое приведение / усечение, если совместимые типы используются правильно, но иногда невозможно обойти несовместимые типы при работе с устаревшими интерфейсами, особенно с низкоуровневыми вызовами ОС.

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

1 голос
/ 06 февраля 2010

Есть аналоги операторов приведения в C ++, определенные в Boost.Lambda , которые очень полезны в различных лямбда-выражениях из простых:

vector<int> v1; // signed indices
v1.push_back(0);
v1.push_back(1);
v1.push_back(2);

vector<size_t> v2(v1.size()); // unsigned +1 incides 
std::transform(v1.begin(), v1.end(), v2.begin(),
(boost::lambda::ll_static_cast<size_t>(boost::lambda::_1) + 1));

намного сложнее с помощью оператора ll_dynamic_cast, например, фильтрация объектов определенного (производного) типа в последовательности :

0 голосов
/ 17 мая 2009

Visual Studio 6 позволял rvalues ​​ связываться с обычными ссылками (не путать с C ++ 0x ссылочными значениями ). При портировании в Visual Studio 2003 все места, где наш код зависел от этого нестандартного поведения, должны были быть изменены.

например. Определение

bool get_string(char* buff, int& length)
{
    if (myStrLength >= length)
    {
        length = myStrLength;
        return false; // Nobody used exceptions in 1998 :o)
    }
    strcpy(buff, myStr);
    return true;
}

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

char buff[1024]; 
get_string(buff, sizeof(buff)); // Assumes size is sufficient 

Чтобы сделать порт намного быстрее, мы написали следующее lvalue_cast.

// Danger, only use this on function arguments that will not be stored
template <class T>
T& lvalue_cast(const T& t)
{
    return const_cast<T&>(t);
}

Поскольку временная область находится в области действия до следующей точки последовательности (следующая точка с запятой), а значения r не являются истинными const s, это хорошо определено (по крайней мере, насколько я понимаю).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...