您通常在模板函数中使用浮点文字做什么?
假设我们有以下代码:
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) };
还是有更优雅的解决方案吗?
答案 0 :(得分:1)
我认为T(5.0)
是最优雅的解决方案。如果T
是double
,那么转换应该被编译器忽略,它与编写5.0
的编译器相同。如果T
是float
,那么转换应该在编译时解决,相当于写为浮点文字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的变量模板。