表达模板化数字文字的最佳方法是什么?

时间:2014-03-13 13:53:48

标签: c++ templates c++11 type-conversion literals

我有一个可以简化为这样的功能:

template<class T>
T foo(T x)
{
  return 123.45 / x;
}

我想确保数字文字1​​23.45与x的类型相同。假设T可以是任何数字类型:signed / unsigned char to long-long或float to long-double。

表明123.45应该是T型的最现代的方法是什么?

我的要求

  • 不应发出任何警告(每次警告都会打开)。
  • 我希望十进制数123.45在计算中使用时具有T的精度。
  • 我想要实现这些目标的最优雅的解决方案。

正在考虑的问题

  • “旧式演员”,即(T)123.45在C ++中基本上已被弃用。
  • static_cast<T>(123.45)似乎是正确的演员类型。但是,它很冗长,我从来没有在文字中看到过这种情况。
  • 我不确定是否需要后缀(例如123.45L)以便在T为long double的情况下获得最大精度,或者编译器是否会自动使用最高精度小数 - 到二进制转换。

更新5-7-2014

在我的代码库中将数百个强制转换更改为T(123.45)形式后,我发现有时这种语法不可用。例如,您不能执行long double(123.45),因为C ++不支持多字节类型构造函数。在这些情况下,我选择了static_cast<long double>(123.45)

5 个答案:

答案 0 :(得分:3)

static_cast是要走的路。这就是C cast等同于任何保留原始含义但会改变值类型的转换。

如果它是具有数字特征的类类型,static_cast将调用单参数构造函数,甚至是explicit构造函数。

如果您想避免缩小转化次数,可以使用语法T{ 123.45 }。这不像C风格的强制转换,但使用直接列表初始化。它仍然允许explicit构造函数,但是对其参数类型的任何数值转换都必须精确。 (不允许溢出或舍入。对于文字,检查特定值的约束,而不是类型之间的关系。但是,当我将12.0传递给int时,GCC会发出警告;我不是确定是否正确。)

答案 1 :(得分:3)

静态演员是自然的。如果你还没有看到它,那么,不是每个人都能看到发生的一切:-)我倾向于使用C风格的演员表(a)我知道两种类型都涉及,(b)我有权懒得。正如您将在下面的代码中看到的那样。

如果您想要LT更精确的精度,

需要double后缀。潜在的static_cast<long double>(123.45) != 123.45L

假设T是一些更精确的类型,例如来自GMP的mpf_class或超出long double的某些特定于编译器的扩展类型。您可能需要考虑boost::lexical_cast<T>("123.45")。当然,这对整数类型不起作用,你需要两个单独的enable_if或其他案例。

另请注意,如果T是排名低于int的整数类型,则例如short(123.45) / xint(123.45) / x相同,因为除法在{ {1}}无论哪种方式和int。如果short(123.45) == int(123.45)是比T更高级别的整数类型,那么例如int 仍然long(123.45) / x相同,因为该分部将是以任意方式int(123.45) / xT执行。此分析依赖于int(123.45) == long(123.45)在任何整数类型[*]中具有相同值的事实。如果您可以将123转换为123.45,那么事情可能会有所不同。例如T

[*]我忽略了-1 / (unsigned char)2 != (unsigned char)-1 / (unsigned char)2,我实际上无法记住它是否是数字类型。

答案 2 :(得分:3)

一个简单的

template<class T>
T foo(T x)
{
  return T(123.45) / x;
}

允许自定义数字类接受构造函数中的值。

答案 3 :(得分:1)

您也可以尝试以下列方式执行此操作:

// RealConstant.h

template <typename Real>
class RealConstant
{
public:

    static 
    const Real value;

};

#define REAL_CONSTANT_DECLARATION(Real) \
template <> \
const Real RealConstant<Real>::value;

REAL_CONSTANT_DECLARATION(float)
REAL_CONSTANT_DECLARATION(double)
REAL_CONSTANT_DECLARATION(long double)

#undef REAL_CONSTANT_DECLARATION


// RealConstant.cpp

#include "RealConstant.h"

#define REAL_CONSTANT_DEFINITION(Real, constantValue) \
template <> \
const Real RealConstant<Real>::value = constantValue;

REAL_CONSTANT_DEFINITION(float, 123.45f)
REAL_CONSTANT_DEFINITION(double, 123.45)
REAL_CONSTANT_DEFINITION(long double, 123.45L)

#undef REAL_CONSTANT_DEFINTION


// File in which `foo` function template is defined

#include "RealConstant.h"

template<class T>
T foo(T x)
{
    return RealConstant<T>::value / x;
}

当然不需要宏。

答案 4 :(得分:0)

我会从文字中初始化一个常量T

template<class T>
T foo(T x)
{
  const T magic = 123.45;
  return magic / x;
}

它同时比static_cast更明确,更易读,更重要的是让您有机会用正确的名称记录幻数;)