如何避免使用模板函数内的浮点文字缩小转换范围

时间:2017-10-18 06:43:38

标签: c++ floating-point

您通常在模板函数中使用浮点文字做什么?

假设我们有以下代码:

template <typename T>
struct Foo
{
    T bar;
};

template <typename T>
void foo(T val)
{
    Foo<T> instance = { val * 5.0 };
}

int main()
{
    foo(0.0f);
}

http://coliru.stacked-crooked.com/a/b159117097cc2461

它给出了以下警告/错误(取决于编译器/标志):

narrowing conversion of '(((double)val) * 5.0e+0)' from 'double' to 'float' inside { } [-Wnarrowing]
     Foo<T> instance = { val * 5.0 };

通常如何避免?我应该在T(0.0)中包装任何浮点文字,如:

Foo<T> instance = { val * T(5.0) };

还是有更优雅的解决方案吗?

3 个答案:

答案 0 :(得分:1)

我认为T(5.0)是最优雅的解决方案。如果Tdouble,那么转换应该被编译器忽略,它与编写5.0的编译器相同。如果Tfloat,那么转换应该在编译时解决,相当于写为浮点文字5.0f

答案 1 :(得分:1)

如果您只处理少量明确定义的魔术常量,但是您需要完全控制所有可能T的常量值,那么将它们移动到traits类可能是有意义的:

template<typename T>
struct FooTraits;

template<>
struct FooTraits<float> { static constexpr float magicN() { return 5.0f; } };

template<>
struct FooTraits<double> { static constexpr double magicN() { return 5.0; } };

template <typename T>
void foo(T val)
{
     Foo<T> instance = { val * FooTraits<T>::magicN() };
}

这是样板文件的一些重要开销,所以只有在你真正需要增加灵活性时才这样做。如果T的简单转换适用于您的所有用例,则没有任何问题。

答案 2 :(得分:1)

  

通常如何避免?

我不认为你应该'避免'它本身,我会说这取决于最终的函数语义。

也就是说,如果你想禁止缩小,你可以使用{}并让编译失败(至少,从> = c ++ 11开始); 如果你想在最终结果上缩小到T,你可以写instance = T( val * 5.0 )并让转换为每个可能的T做剩下的工作; 如果你想在 intermidiate 结果或常量中缩小到T,你可以在那里包裹T(); 如果您希望用户决定,您可以添加执行最终/中间转换的特征/策略类...

说,有一件事我肯定:作为你的功能的使用者,如果上述任何可能性没有记载,或者根据功能最终目标不合理,我会感到非常不舒服......

顺便说一句,如果你的问题只关注常数,那么我可以关注boost approach,也许借助c ++ 14的变量模板。