Making auto_cast safe

Making auto_cast safe

本文关键字:safe cast auto Making      更新时间:2023-10-16

GMan发布了一个美味的auto_cast "运算符"代码,允许在c++中编写如下代码:

float f = 4.0f;
int i = auto_cast(f);
// instead of:
int j = static_cast<int>(f);

或者更明显的

T x = value;
typename nested_type<with, template_arguments>::type y = auto_cast(x);
// instead of
typedef typename nested_type<with, template_arguments>::type my_type;
my_type z = static_cast<my_type>(x);

基本上,操作员可以很好地从static_cast中去除不必要的冗余,同时仍然是安全的。它甚至比static_cast安全,因为它可以防止意外的类型不匹配:

int i = 1234;
short s = static_cast<char>(i); // s == -46, not 1234!

然而,j_random_hacker注意到了操作符中的一个缺陷:

static_cast允许向下转换,这可能是不安全的。

实际上,auto_cast可能应该禁止向下转换,因为它们可能会失败:

class base { };
class derived : public base { };
base b;
derived* pd = auto_cast(&b); // should fail at compile time.

所以我的问题是:

如何修改auto_cast实现以禁止向下转换?这可能涉及enable_if。我特别感兴趣的是一种解决方案,它允许编译器在出现故障时提供良好的诊断(=可读的错误消息)。

看来您想使用T{u}形式的初始化。

template <typename U>
operator U()
{
    return U{std::forward<T>(mX)};
}

这些统一初始化的原因之一是,为了使用显式构造函数创建临时对象,您需要一个称为T(u)的强制类型转换。T{u}解决了这个问题。对于c++ 03,我想您可以这样做:

template<typename T>
struct construct_explicit {
  template<typename U>
  construct_explicit(U &u):t(u) { }
  template<typename U>
  construct_explicit(U const &u):t(u) { }
  T &get() { return t; }
  T const& get() const { return t; }
  T t;
};

然后你可以说construct_explicit<U>(mX).get(),尽管在转换函数中,它也可以使用命名变量作为中间步骤,我认为

template <typename U>
operator U()
{
    // or C++03: U u(mX);
    U u(std::forward<T>(mX));
    return u;
}

如果TR的基,则可以使用type-traits来禁用操作符。在c++ 0x中,可以显式地使用static_assert(std::is_base_of<T, U>::value, "Cannot auto_cast downwards!");

我甚至不会使用auto_cast,因为static_cast, const_cast, dynamic_cast和reinterpret_cast也被设计得很难看,以帮助指出可能需要重构的代码:一个难看的操作应该有一个难看的外观。

的第二个原因新式演员是c型演员在节目中很难被发现。例如,你不能方便地使用普通类型搜索强制转换编辑器或文字处理机。这几乎不可见的c风格强制转换尤其不幸的是都具有潜在的破坏性。一个丑陋的操作应该是丑陋的语法形式。这个观察结果是选择的部分原因是新样式强制转换的语法。一个进一步的原因是新的风格强制转换以匹配模板表示法;这样程序员就可以编写他们的自己的强制转换,特别是运行时检查投。

http://www2.research.att.com/~ bs/bs_faq2.html # static-cast

我更喜欢在代码中清楚地看到它可以更好的地方,或者我们明确地需要做这个丑陋的操作。