在C ++中可以使用哪些其他有用的强制转换

时间:2022-09-06 18:34:35

C++ comes with four built-in casts.

C ++附带了四个内置的强制转换。

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

Not to meantion the frowned upon C (style*)cast.

不要贬低C(风格*)演员的皱眉。

Additionally boost supplies a lexical_cast, are there any other useful casts that you use or would like to exist?

另外,boost提供了lexical_cast,你还有其他任何有用的演员阵容吗?

10 个解决方案

#1


My favorite and most loved cast is implicit_cast. It only succeeds if the types can be implicitly converted.

我最喜欢和最喜欢的演员是implicit_cast。只有在可以隐式转换类型时才能成功。

Useful for conversion from some type into void* or from some derived class into a base (if you want to select a specific instance of an overloaded function or constructor) or to safely add const-qualifications and any other scenario where you really just need implicit conversions to happen and even static_cast is too powerful.

用于从某种类型转换为void *或从某些派生类转换为基类(如果要选择重载函数或构造函数的特定实例)或安全地添加const-qualifications以及您真正需要隐式的任何其他场景转换发生甚至static_cast太强大了。

Also read How does C++ pick which overload to call.

另请阅读C ++如何选择要调用的重载。

boost/implicit_cast.hpp. You can add this to your code collection too, if you want

提升/ 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


There's also the function-style cast which looks like a function or constructor call. This resolves to the constructor call for classes, and (more generally) to C-style casts for all other types.

还有函数样式转换,看起来像函数或构造函数调用。这解析为类的构造函数调用,并且(更一般地)解析为所有其他类型的C样式转换。

Examples:

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

The call to a constructor can also be achived using an explicit cast (apart from the C-style cast which would also work):

对构造函数的调用也可以使用显式强制转换(除了C样式的强制转换也可以使用):

string s = static_cast<string>("x"); // is the same as above!

#3


It's worth remembering that constructors can also be considered to act as casts, and will be used by the compiler to perform cast-like conversions. For example:

值得记住的是,构造函数也可以被视为强制转换,并且编译器将使用它来执行类似转换的转换。例如:

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

The Person constructor acts a conversion from string -> Person:

Person构造函数从字符串 - > Person执行转换:

Person p = Person( "fred" );

and will be used by the compiler when a string needs to conversted to a person:

当一个字符串需要与一个人交谈时,编译器将使用它:

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

the compiler can now convert a string to a Person:

编译器现在可以将字符串转换为Person:

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

but note that it cannot do this:

但请注意,它不能这样做:

PrintPerson( "fred" );

as this would require the compiler to construct a chain of conversions.

因为这需要编译器构建一系列转换。

Edit: I have posted a follow-up question on the topic of conversions - see C++ implicit conversions.

编辑:我发布了有关转换主题的后续问题 - 请参阅C ++隐式转换。

#4


You might want to use the boost pointer casts (boost::static_pointer_cast,...) if you use shared_ptr. They can also be used for standard pointers.

如果使用shared_ptr,您可能希望使用boost指针强制转换(boost :: static_pointer_cast,...)。它们也可用于标准指针。

#5


One really useful boost cast is operator (function really) is numeric_cast(number);

一个非常有用的提升演员是operator(函数确实)是numeric_cast(数字);

This checks that the number you are casting is in range for the destination type.

这将检查您要投射的数字是否在目标类型的范围内。

eg

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


There is also a horrid union_cast.

还有一个可怕的union_cast。

It's bad because strictly speaking it is UB, but if you know what you are doing, it can be useful for converting pointers to member functions to void* and back, not all compilers allow to do this with reinterpret_cast.

这很糟糕,因为严格来说它是UB,但是如果你知道你在做什么,那么将指向成员函数的指针转换为void *并返回它是有用的,并非所有编译器都允许使用reinterpret_cast执行此操作。

But still it's better avoided..

但仍然最好避免..

#7


ACE has a truncate_cast. It is mostly useful for optimizing code like the following:

ACE有一个truncate_cast。它对于优化代码非常有用,如下所示:

foo_t bar = ...;
short baz;

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

This could be replaced by:

这可以替换为:

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

Depending on the underlying type of foo_t, truncate_cast will optimize away the if() statement entirely, and also address compiler diagnostics resulting from comparison of signed and unsigned types. The choice of which way to go is performed at compile-time through a template metaprogram.

根据foo_t的基础类型,truncate_cast将完全优化if()语句,并解决由有符号和无符号类型的比较产生的编译器诊断。选择哪种方式是在编译时通过模板元程序执行的。

Ideally one should not need such a cast/truncation if compatible types are used correctly but sometimes there's no getting around incompatible types when working with legacy interfaces, particularly with low level OS calls.

理想情况下,如果正确使用兼容类型,则不应该需要这样的强制转换/截断,但有时在使用传统接口时不会出现不兼容的类型,特别是对于低级别的OS调用。

Note that it's easy to abuse such a cast, which is why the authors explictly state it is meant for internal use, and that the cast shouldn't be used to work around compiler diagnostics.

请注意,滥用此类强制转换很容易,这就是作者明确表示它是供内部使用的原因,并且不应使用强制转换来解决编译器诊断问题。

#8


memcpy_cast is a strictly Standard-compliant thus safe and portable alternative to type punning:

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

(where STATIC_ASSERT is some compile-time assertion macro (or C++11's static_assert), and the constraints come from STLSoft's union_cast.hpp).

(其中STATIC_ASSERT是一些编译时断言宏(或C ++ 11的static_assert),而约束来自STLSoft的union_cast.hpp)。

You can then try things like

然后你可以尝试类似的东西

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

(Here's another implementation: dbg's memcpy_cast.hpp.)

(这是另一个实现:dbg的memcpy_cast.hpp。)

(Edit: Also, Boost.SIMD has a bitwise_cast which internally uses a memcpy_cast.)

(编辑:另外,Boost.SIMD有一个bitwise_cast,内部使用memcpy_cast。)

#9


There are counterparts of C++ casting operators defined in Boost.Lambda which are very useful in various lambda expressions from simple ones:

在Boost.Lambda中定义了C ++转换运算符的对应物,它们在各种简单的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));

to much more complex using ll_dynamic_cast operator, for instance, to filter objects of particular (derived) type in a sequence:

例如,使用ll_dynamic_cast运算符来更复杂地过滤序列中特定(派生)类型的对象:

#10


Visual Studio 6 allowed rvalues to bind to regular references (not to be mistaken with C++0x's rvalue references). When porting to Visual Studio 2003 all the places that our code depended on this non-standard behaviour had to be changed.

Visual Studio 6允许rvalues绑定到常规引用(不要误解为C ++ 0x的rvalue引用)。移植到Visual Studio 2003时,必须更改我们的代码依赖于此非标准行为的所有位置。

E.g. Definition

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

Usage:

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

In order to make the port much faster we wrote the following lvalue_cast.

为了使端口更快,我们编写了以下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);
}

Since the temporary is in scope till the next sequence point (the next semi-colon) and rvalues aren't true consts this is well defined (to my understanding at least).

由于临时在范围内,直到下一个序列点(下一个分号)和rvalues不是真正的consts,这是明确定义的(至少我的理解)。

#1


My favorite and most loved cast is implicit_cast. It only succeeds if the types can be implicitly converted.

我最喜欢和最喜欢的演员是implicit_cast。只有在可以隐式转换类型时才能成功。

Useful for conversion from some type into void* or from some derived class into a base (if you want to select a specific instance of an overloaded function or constructor) or to safely add const-qualifications and any other scenario where you really just need implicit conversions to happen and even static_cast is too powerful.

用于从某种类型转换为void *或从某些派生类转换为基类(如果要选择重载函数或构造函数的特定实例)或安全地添加const-qualifications以及您真正需要隐式的任何其他场景转换发生甚至static_cast太强大了。

Also read How does C++ pick which overload to call.

另请阅读C ++如何选择要调用的重载。

boost/implicit_cast.hpp. You can add this to your code collection too, if you want

提升/ 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


There's also the function-style cast which looks like a function or constructor call. This resolves to the constructor call for classes, and (more generally) to C-style casts for all other types.

还有函数样式转换,看起来像函数或构造函数调用。这解析为类的构造函数调用,并且(更一般地)解析为所有其他类型的C样式转换。

Examples:

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

The call to a constructor can also be achived using an explicit cast (apart from the C-style cast which would also work):

对构造函数的调用也可以使用显式强制转换(除了C样式的强制转换也可以使用):

string s = static_cast<string>("x"); // is the same as above!

#3


It's worth remembering that constructors can also be considered to act as casts, and will be used by the compiler to perform cast-like conversions. For example:

值得记住的是,构造函数也可以被视为强制转换,并且编译器将使用它来执行类似转换的转换。例如:

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

The Person constructor acts a conversion from string -> Person:

Person构造函数从字符串 - > Person执行转换:

Person p = Person( "fred" );

and will be used by the compiler when a string needs to conversted to a person:

当一个字符串需要与一个人交谈时,编译器将使用它:

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

the compiler can now convert a string to a Person:

编译器现在可以将字符串转换为Person:

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

but note that it cannot do this:

但请注意,它不能这样做:

PrintPerson( "fred" );

as this would require the compiler to construct a chain of conversions.

因为这需要编译器构建一系列转换。

Edit: I have posted a follow-up question on the topic of conversions - see C++ implicit conversions.

编辑:我发布了有关转换主题的后续问题 - 请参阅C ++隐式转换。

#4


You might want to use the boost pointer casts (boost::static_pointer_cast,...) if you use shared_ptr. They can also be used for standard pointers.

如果使用shared_ptr,您可能希望使用boost指针强制转换(boost :: static_pointer_cast,...)。它们也可用于标准指针。

#5


One really useful boost cast is operator (function really) is numeric_cast(number);

一个非常有用的提升演员是operator(函数确实)是numeric_cast(数字);

This checks that the number you are casting is in range for the destination type.

这将检查您要投射的数字是否在目标类型的范围内。

eg

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


There is also a horrid union_cast.

还有一个可怕的union_cast。

It's bad because strictly speaking it is UB, but if you know what you are doing, it can be useful for converting pointers to member functions to void* and back, not all compilers allow to do this with reinterpret_cast.

这很糟糕,因为严格来说它是UB,但是如果你知道你在做什么,那么将指向成员函数的指针转换为void *并返回它是有用的,并非所有编译器都允许使用reinterpret_cast执行此操作。

But still it's better avoided..

但仍然最好避免..

#7


ACE has a truncate_cast. It is mostly useful for optimizing code like the following:

ACE有一个truncate_cast。它对于优化代码非常有用,如下所示:

foo_t bar = ...;
short baz;

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

This could be replaced by:

这可以替换为:

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

Depending on the underlying type of foo_t, truncate_cast will optimize away the if() statement entirely, and also address compiler diagnostics resulting from comparison of signed and unsigned types. The choice of which way to go is performed at compile-time through a template metaprogram.

根据foo_t的基础类型,truncate_cast将完全优化if()语句,并解决由有符号和无符号类型的比较产生的编译器诊断。选择哪种方式是在编译时通过模板元程序执行的。

Ideally one should not need such a cast/truncation if compatible types are used correctly but sometimes there's no getting around incompatible types when working with legacy interfaces, particularly with low level OS calls.

理想情况下,如果正确使用兼容类型,则不应该需要这样的强制转换/截断,但有时在使用传统接口时不会出现不兼容的类型,特别是对于低级别的OS调用。

Note that it's easy to abuse such a cast, which is why the authors explictly state it is meant for internal use, and that the cast shouldn't be used to work around compiler diagnostics.

请注意,滥用此类强制转换很容易,这就是作者明确表示它是供内部使用的原因,并且不应使用强制转换来解决编译器诊断问题。

#8


memcpy_cast is a strictly Standard-compliant thus safe and portable alternative to type punning:

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

(where STATIC_ASSERT is some compile-time assertion macro (or C++11's static_assert), and the constraints come from STLSoft's union_cast.hpp).

(其中STATIC_ASSERT是一些编译时断言宏(或C ++ 11的static_assert),而约束来自STLSoft的union_cast.hpp)。

You can then try things like

然后你可以尝试类似的东西

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

(Here's another implementation: dbg's memcpy_cast.hpp.)

(这是另一个实现:dbg的memcpy_cast.hpp。)

(Edit: Also, Boost.SIMD has a bitwise_cast which internally uses a memcpy_cast.)

(编辑:另外,Boost.SIMD有一个bitwise_cast,内部使用memcpy_cast。)

#9


There are counterparts of C++ casting operators defined in Boost.Lambda which are very useful in various lambda expressions from simple ones:

在Boost.Lambda中定义了C ++转换运算符的对应物,它们在各种简单的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));

to much more complex using ll_dynamic_cast operator, for instance, to filter objects of particular (derived) type in a sequence:

例如,使用ll_dynamic_cast运算符来更复杂地过滤序列中特定(派生)类型的对象:

#10


Visual Studio 6 allowed rvalues to bind to regular references (not to be mistaken with C++0x's rvalue references). When porting to Visual Studio 2003 all the places that our code depended on this non-standard behaviour had to be changed.

Visual Studio 6允许rvalues绑定到常规引用(不要误解为C ++ 0x的rvalue引用)。移植到Visual Studio 2003时,必须更改我们的代码依赖于此非标准行为的所有位置。

E.g. Definition

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

Usage:

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

In order to make the port much faster we wrote the following lvalue_cast.

为了使端口更快,我们编写了以下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);
}

Since the temporary is in scope till the next sequence point (the next semi-colon) and rvalues aren't true consts this is well defined (to my understanding at least).

由于临时在范围内,直到下一个序列点(下一个分号)和rvalues不是真正的consts,这是明确定义的(至少我的理解)。