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
。我特别感兴趣的是一种解决方案,它允许编译器在出现故障时提供良好的诊断(=可读的错误消息)。
答案 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)
如果T
是R
的基础,您可以使用类型特征来禁用运算符。由于我们在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
我更愿意在代码中清楚地看到它可能更好,或者我们明确需要做出这种丑陋的操作。