`static_cast <bool>(x)`和`x!= 0.0`之间有区别吗?</bool>

时间:2013-07-10 21:06:57

标签: c++ templates casting warnings

设置

我正在使用名为MotionBuilder的应用程序的API。为了访问MotionBuilder属性的值,无论它实际代表什么类型的数据类型,都将其读入双变量。

这是我编写的用于评估标量属性值的实用函数:

template <typename DataT>
inline DataT GetScalar(FBProperty& prop, FBEvaluateInfo* evaluateInfo)
{
    double data = 0.0;
    prop.GetData(&data, sizeof(data), evaluateInfo);
    return static_cast<DataT>(data);
}

通过这种方式,我可以编写GetScalar<float>(camera.Roll, evaluateInfo)GetScalar<bool>(camera.Visibility, evaluateInfo),而不是使用多行未处理的缓冲区和强制转换我的代码。

我正在使用/W4在Visual Studio中进行编译,并在出现时解决所有警告。当我使用GetScalar<bool>时,编译器会生成a C4800 warning

'double' : forcing value to bool 'true' or 'false' (performance warning)

当编译器创建GetScalar<bool>时,它会从一个double到bool的static_cast结束,这显然是不喜欢的。由于我最初的目标是使用单个模板函数处理多种类型(bool,float,double等),因此我不能只添加通常的!= 0.0

为了解决这个警告,我有两个选择。

选项1

我可以直接用pragma来抑制警告,因为演员阵容正是我想做的事情:

template <typename DataT>
inline DataT GetScalar(FBProperty& prop, FBEvaluateInfo* evaluateInfo)
{
    double data = 0.0;
    prop.GetData(&data, sizeof(data), evaluateInfo);
#pragma warning (push)
#pragma warning (disable: 4800) // Don't complain about casting to bool
    return static_cast<DataT>(data);
#pragma warning (pop)
}

选项2

我可以添加GetScalar的专精来处理bool案例:

template <>
inline bool GetScalar<bool>(FBProperty& prop, FBEvaluateInfo* evaluateInfo)
{
    double data = 0.0;
    prop.GetData(&data, sizeof(data), evaluateInfo);
    return data != 0.0;
}

问题

我认为对于某些双x,static_cast<bool>(x)完全等同于x != 0.0。实际上,在发布模式下编译的简单测试在两种情况下都给出了相同的汇编输出。那么,为什么C4800称自己为“性能警告?”以上概述的两个选项在功能上是否相同?如果归结为时尚问题,在穿上你最好的学步帽后,您更喜欢哪种选择?

4 个答案:

答案 0 :(得分:3)

我认为对于bool的情况,与0的比较比强制转换更具可读性。我还要问一下,在语义上是否有意义,有一个专门用于数字类型的函数和bool具有相同的实现,即使这恰好在这里工作。

一般。在您的特定情况下,我认为拥有一个统一的模板是好的,如果它避免代码重复,这是一个优势。如果有的话,我可能只会为cast-to - DataT部分创建一个函数专门化,而不是整个函数:

template <typename T>
T convertTo(double d) { return static_cast<T>(d); }

template <>
double convertTo<bool>(double d) { return d != 0.0; }

template <typename DataT>
inline DataT GetScalar(FBProperty& prop, FBEvaluateInfo* evaluateInfo)
{
    double data = 0.0;
    prop.GetData(&data, sizeof(data), evaluateInfo);
    return convertTo<DataT>(data);
}

或者你可以选择性地禁用警告,但如果你这样做,请在评论中解释为什么这里有必要。

答案 1 :(得分:3)

我不确定您的特定设置的最佳解决方案是什么(我认为静态转换为bool非常好),但处理分支的一般方法是为每个单独的操作创建单独的特征。在你的情况下,那是“convert_to_bool”:

template <typename Out>
struct converter
{
    static Out from_double(double x)
    {
        return static_cast<Out>(x);
    }
};

template <>
struct converter<bool>
{
    static bool from_double(double x)
    {
        return x != 0;
    }
};

现在你可以使用:

return converter<DataT>::from_double(data);

通过这种方式,您可以处理主模板中出现的所有情况,并且需要对某些类型进行特殊处理,而无需分支主模板。

答案 2 :(得分:3)

这是警告,它告诉您此转换可能存在性能问题。既然你想进行转换,那就去做吧。不要浪费时间为没有告诉你任何有用的警告编写精心设计的变通方法。

答案 3 :(得分:0)

这是极少数情况下我会使用演员的功能表示版本而不是static_cast。编译器不会发出任何警告,因为这种形式的演员有效地告诉它你'知道你在做什么'。

template <typename DataT>
inline DataT GetScalar(FBProperty& prop, FBEvaluateInfo* evaluateInfo)
{
    double data = 0.0;
    prop.GetData(&data, sizeof(data), evaluateInfo);
    return DataT(data);
}

一般来说,要注意在C ++中使用这种类型的强制转换,因为它可以抑制有意义的警告。我只会在算术类型(例如intdoubleenum)之间使用它来抑制警告,当我不关心处理溢出时。