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

时间:2009-05-14 11:40:44

标签: c++ casting

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

  1. static_cast
  2. dynamic_cast
  3. const_cast
  4. reinterpret_cast
  5. 不要轻视C (style*)cast

    此外boost提供lexical_cast,您使用或想要存在的其他任何有用的演员表是否存在?

10 个答案:

答案 0 :(得分:10)

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

用于从某种类型转换为void*或从某些派生类转换为基类(如果要选择重载函数或构造函数的特定实例)或安全地添加常量资格和任何其他方案你真正需要进行隐式转换的地方甚至static_cast太强大了。

另请阅读How does C++ pick which overload to call

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

答案 1 :(得分:9)

还有函数样式转换,它看起来像一个函数或构造函数调用。这解析为构造函数对类的调用,并且(更一般地)解析为所有其他类型的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!

答案 2 :(得分:8)

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

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

Person构造函数从string - &gt;进行转换。人:

Person p = Person( "fred" );
当需要将字符串转换为某个人时,编译器将使用

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

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

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

但请注意,它无法执行此操作:

PrintPerson( "fred" );

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

修改:我发布了有关转化主题的后续问题 - 请参阅C++ implicit conversions

答案 3 :(得分:4)

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

答案 4 :(得分:4)

一个非常有用的助推器是操作员(功能真的)是 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

答案 5 :(得分:3)

还有一个可怕的union_cast

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

但是最好还是避免..

答案 6 :(得分:2)

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()语句,并解决由此产生的编译器诊断问题。有符号和无符号类型的比较。选择哪种方式是在编译时通过模板元程序执行的。

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

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

答案 7 :(得分:2)

memcpy_cast严格遵守标准,因此是 type punning 的安全便携替代品:

#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),约束来自STLSoft's union_cast.hpp)。

然后你可以尝试像

这样的事情
uint32_t u = 0x1234ABCD;
//float f = *(float*)&u; // unsafe
float f = memcpy_cast<float>(u); // safe

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

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

答案 8 :(得分:1)

Boost.Lambda中定义了C ++强制转换运算符的对应部分,它们在简单的lambda expressions中非常有用:

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运算符比较复杂,例如filter objects of particular (derived) type in a sequence

答案 9 :(得分:0)

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

<强> E.g。定义

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

由于临时在范围内直到下一个sequence point (下一个分号)并且rvalues不是真const s,这是明确定义的(至少我的理解)。