Подтвердить что ты не робот

Какие другие полезные приемы могут использоваться в С++

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

  • static_cast
  • dynamic_cast
  • const_cast
  • reinterpret_cast

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

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

4b9b3361

Ответ 1

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

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

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

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; }

Ответ 2

Также существует функциональный стиль, который выглядит как вызов функции или конструктора. Это разрешает вызов конструктора для классов и (в более общем смысле) для 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!

Ответ 3

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

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" );

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

Изменить: Я опубликовал следующий вопрос по теме конверсий - см. неявные преобразования С++.

Ответ 4

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

Ответ 5

Одно действительно полезное повышение - оператор (функция действительно) - это 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

Ответ 6

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

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

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

Ответ 7

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() целиком, а также диагностику компилятора адреса в результате сравнение подписанных и неподписанных типов. Выбор того, как идти, выполняется во время компиляции через шаблонную метапрограмму.

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

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

Ответ 8

memcpy_cast является строго стандартным, таким образом безопасным и переносимым альтернативом типа punning:

#include <cstring>

template<typename To, typename From>
inline To memcpy_cast(From x)
{
    // Constraints on types from STLSoft 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 - некоторый макрос утверждения времени компиляции (или С++ 11 STATIC_ASSERT), а ограничения связаны с STLSoft union_cast.hpp).

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

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

(Здесь другая реализация: dbg memcpy_cast.hpp.)

(Edit: Кроме того, Boost.SIMD имеет bitwise_cast, который внутренне использует memcpy_cast.)

Ответ 9

Существуют экземпляры операторов каста С++, определенные в 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, например, фильтровать объекты определенного (производного) типа в последовательности:

Ответ 10

Visual Studio 6 разрешает rvalues ​​ привязываться к регулярным ссылкам (не ошибиться с С++ 0x rvalue references). При переносе в 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 не соответствуют true const это хорошо определено (по крайней мере, по моему мнению).