yok*_*kks 107 c++ generics floating-point templates
当我尝试float用作模板参数时,编译器会为此代码而烦恼,同时int工作正常.
是因为我不能float用作模板参数吗?
#include<iostream>
using namespace std;
template <class T, T defaultValue>
class GenericClass
{
private:
T value;
public:
GenericClass()
{
value = defaultValue;
}
T returnVal()
{
return value;
}
};
int main()
{
GenericClass <int, 10> gcInteger;
GenericClass < float, 4.6f> gcFlaot;
cout << "\n sum of integer is "<<gcInteger.returnVal();
cout << "\n sum of float is "<<gcFlaot.returnVal();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
错误:
main.cpp: In function `int main()':
main.cpp:25: error: `float' is not a valid type for a template constant parameter
main.cpp:25: error: invalid type in declaration before ';' token
main.cpp:28: error: request for member `returnVal' in `gcFlaot',
which is of non-class type `int'
Run Code Online (Sandbox Code Playgroud)
我正在阅读Ron Penton撰写的"游戏程序员的数据结构",作者传递了一个float,但是当我尝试它时似乎没有编译.
Fil*_*efp 128
该标准不允许浮点作为非类型模板参数,可以在C++ 11标准的以下部分中阅读;
14.3.2/1模板非类型参数[temp.arg.nontype]
非类型非模板模板参数的模板参数应为以下之一:
对于整数或枚举类型的非类型模板参数,模板参数类型的转换常量表达式(5.19);
非类型模板参数的名称; 要么
一个常量表达式(5.19),用于指定具有静态存储持续时间和外部或内部链接的对象的地址,或具有外部或内部链接的函数,包括函数模板和函数模板-id,但不包括非静态类成员,表示(忽略)括号)as&id-expression,除非如果名称引用函数或数组,可以省略&,如果相应的template-parameter是引用,则省略; 要么
一个常量表达式,其值为空指针值(4.10); 要么
一个常量表达式,其值为null成员指针值(4.11); 要么
指向成员的指针,如5.3.1中所述.
这可能是由于浮点计算无法以精确的方式表示.如果它被允许它可能/会在做这样的事情时导致错误/奇怪的行为;
func<1/3.f> ();
func<2/6.f> ();
Run Code Online (Sandbox Code Playgroud)
我们打算两次调用相同的函数,但这可能不是这种情况,因为两个计算的浮点表示不能保证完全相同.
随着C++11你可以写一些非常先进的常量表达式(constexpr),将计算出的浮动值的分子/分母编译时间,然后通过这两个作为单独的整数参数.
请记住定义某种阈值,使浮点值彼此接近,产生相同的分子/分母,否则它有点无意义,因为它会产生前面提到的相同结果,作为不允许浮点值为 非类型的原因模板参数.
小智 34
当前的C++标准不允许float(即实数)或字符串文字用作模板非类型参数.您当然可以使用float和char *类型作为普通参数.
也许作者使用的编译器不遵循现行标准?
Ric*_*den 31
只是提供这是一个限制的原因之一(至少在目前的标准中).
匹配模板特化时,编译器会匹配模板参数,包括非类型参数.
就其本质而言,浮点值并不精确,并且C++标准未指定它们的实现.因此,很难确定两个浮点非类型参数何时真正匹配:
template <float f> void foo () ;
void bar () {
foo< (1.0/3.0) > ();
foo< (7.0/21.0) > ();
}
Run Code Online (Sandbox Code Playgroud)
这些表达式不一定产生相同的"位模式",因此不可能保证它们使用相同的特化 - 没有特殊的措辞来涵盖这一点.
moo*_*dow 18
实际上,您不能将浮点文字用作模板参数.参见14.1节 ("非类型模板参数应具有以下标准之一(可选择cv限定)......").
您可以使用float的引用作为模板参数:
template <class T, T const &defaultValue>
class GenericClass
.
.
float const c_four_point_six = 4.6; // at global scope
.
.
GenericClass < float, c_four_point_six> gcFlaot;
Run Code Online (Sandbox Code Playgroud)
将参数作为constexp包装在自己的类中.实际上,这类似于特征,因为它使用一组浮点数对类进行参数化.
class MyParameters{
public:
static constexpr float Kd =1.0f;
static constexpr float Ki =1.0f;
static constexpr float Kp =1.0f;
};
Run Code Online (Sandbox Code Playgroud)
然后创建一个模板,将类类型作为参数
template <typename NUM, typename TUNING_PARAMS >
class PidController {
// define short hand constants for the PID tuning parameters
static constexpr NUM Kp = TUNING_PARAMS::Kp;
static constexpr NUM Ki = TUNING_PARAMS::Ki;
static constexpr NUM Kd = TUNING_PARAMS::Kd;
.... code to actually do something ...
};
Run Code Online (Sandbox Code Playgroud)
然后像这样使用它......
int main (){
PidController<float, MyParameters> controller;
...
...
}
Run Code Online (Sandbox Code Playgroud)
这允许编译器保证仅为具有相同参数包的每个模板实例创建单个代码实例.这解决了所有问题,你可以在模板化的类中使用浮点数和双精度作为constexpr.
从 C++20 开始,这是可能的。
这也给出了原始问题的答案:
Why can't I use float value as a template parameter?
Run Code Online (Sandbox Code Playgroud)
因为还没有人在标准中实现它。没有根本的原因。
在 C++20 中,非类型模板参数现在可以是浮点数甚至是类对象。
对类对象有一些要求(它们必须是文字类型)并满足一些其他要求以排除病态情况,例如用户定义的运算符 ==(详细信息)。
我们甚至可以使用 auto
template <auto Val>
struct Test {
};
struct A {};
static A aval;
Test<aval> ta;
Test<A{}> ta2;
Test<1.234> tf;
Test<1U> ti;
Run Code Online (Sandbox Code Playgroud)
请注意,GCC 9(和 10)实现了类非类型模板参数,但还没有实现浮点数。
如果可以为每个类型使用固定的默认值,则可以创建一个类型以将其定义为常量,并根据需要对其进行特殊化。
template <typename T> struct MyTypeDefault { static const T value; };
template <typename T> const T MyTypeDefault<T>::value = T();
template <> struct MyTypeDefault<double> { static const double value; };
const double MyTypeDefault<double>::value = 1.0;
template <typename T>
class MyType {
public:
MyType() { value = MyTypeDefault<T>::value; }
private:
T value;
};
Run Code Online (Sandbox Code Playgroud)
如果您具有C ++ 11,则可以在定义默认值时使用constexpr。在C ++ 14中,MyTypeDefault可以是模板变量,从语法上讲它更干净一些。
//C++14
template <typename T> constexpr T MyTypeDefault = T();
template <> constexpr double MyTypeDefault<double> = 1.0;
template <typename T>
class MyType {
private:
T value = MyTypeDefault<T>;
};
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
45875 次 |
| 最近记录: |