使auto_cast安全

时间:2011-04-17 12:12:07

标签: c++ casting

GMan发布了delicious auto_cast “operator”的代码,允许在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。我特别感兴趣的是一种解决方案,它允许编译器在出现故障时提供良好的诊断(=可读的错误消息)。

3 个答案:

答案 0 :(得分:7)

您似乎想要使用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;
}

答案 1 :(得分:3)

如果TR的基础,您可以使用类型特征来禁用运算符。由于我们在C ++ 0x中,您可以明确static_assert(std::is_base_of<T, U>::value, "Cannot auto_cast downwards!");

答案 2 :(得分:2)

我甚至不会使用auto_cast,因为static_cast,const_cast,dynamic_cast和reinterpret_cast在设计上也很丑陋以帮助指向可能需要重构的代码:丑陋的操作应该看起来很难看。

  

引入的第二个原因   新式演员是C风格演员   在一个程序中很难发现。   例如,你不方便   使用普通搜索强制转换   编辑器或文字处理器。这个   近似隐形的C风格演员是   特别不幸,因为他们   是如此潜在的破坏性。一个丑陋的   操作应该有一个难看的   句法形式。那个观察是   选择的部分原因   新样式转换的语法。一个   进一步的原因是新风格   强制转换以匹配模板表示法,   这样程序员就可以编写自己的   自己的演员,特别是运行时检查   管型。

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

我更愿意在代码中清楚地看到它可能更好,或者我们明确需要做出这种丑陋的操作。