왜 float 값을 템플릿 매개 변수로 사용할 수 없습니까?
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;
}
오류:
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'
Ron Penton의 "Data Structures for Game Programmers"를 읽고 있는데 저자는를 전달 float
했지만 시도해도 컴파일되지 않는 것 같습니다.
현재 C ++ 표준에서는 float
(예 : 실수) 또는 문자열 리터럴을 템플릿 비 유형 매개 변수로 사용할 수 없습니다 . 물론 float
및 char *
유형을 일반 인수로 사용할 수 있습니다 .
아마도 저자가 현재 표준을 따르지 않는 컴파일러를 사용하고 있습니까?
간단한 대답
표준은 부동 소수점을 유형이 아닌 template-arguments 로 허용하지 않습니다 . 이는 C ++ 11 표준의 다음 섹션에서 읽을 수 있습니다.
14.3.2 / 1 템플릿 비 유형 인수 [temp.arg.nontype]
유형이 아닌 템플릿 매개 변수에 대한 템플릿 매개 변수는 다음 중 하나 여야합니다.
정수 또는 열거 유형의 비 유형 템플릿 매개 변수의 경우 템플릿 매개 변수 유형의 변환 된 상수 표현식 (5.19)
유형이 아닌 템플릿 매개 변수의 이름 또는
정적 저장 기간 및 외부 또는 내부 연결이있는 객체의 주소를 지정하는 상수 표현식 (5.19) 또는 함수 템플릿 및 함수 템플릿 ID를 포함하지만 비 정적 클래스 멤버를 제외하고 표현 된 (무시) 외부 또는 내부 연결이있는 함수 괄호) as & id-expression, 단, 이름이 함수 또는 배열을 참조하는 경우 &를 생략 할 수 있으며 해당 템플릿 매개 변수가 참조 인 경우 생략되어야합니다. 또는
널 포인터 값 (4.10)으로 평가되는 상수 표현식 또는
널 멤버 포인터 값 (4.11)으로 평가되는 상수 표현식 또는
5.3.1에 설명 된대로 멤버에 대한 포인터.
근데 .. 근데 .. 왜!?
부동 소수점 계산을 정확한 방식으로 표현할 수 없기 때문일 수 있습니다. 만약 그것이 허용된다면, 이것과 같은 일을 할 때 잘못된 / 이상한 행동을하게 될 수 있습니다.
func<1/3.f> ();
func<2/6.f> ();
우리는 동일한 함수를 두 번 호출하려고했지만 두 계산의 부동 소수점 표현이 정확히 동일 하다는 보장이 없기 때문에 그렇지 않을 수도 있습니다 .
부동 소수점 값을 템플릿 인수로 어떻게 표현합니까?
으로 C++11
당신은 꽤 고급 쓸 수있는 상수 표현식 ( constexpr 부동 값 컴파일 시간의 분자 / 분모를 계산 한 후 별도의 정수 인자로이 두 가지를 통과 할 것).
서로 가까운 부동 소수점 값이 동일한 분자 / 분모를 산출하도록 일종의 임계 값을 정의하는 것을 잊지 마십시오. 그렇지 않으면 부동 소수점 값을 유형이 아닌 값으로 허용하지 않는 이유로 이전에 언급 한 동일한 결과를 산출하기 때문에 다소 무의미 합니다. 템플릿 인수 .
이것이 제한 인 이유 중 하나를 제공하기 위해서입니다 (적어도 현재 표준에서는).
템플릿 전문화를 일치시킬 때 컴파일러는 유형이 아닌 인수를 포함하여 템플릿 인수를 일치시킵니다.
본질적으로 부동 소수점 값은 정확하지 않으며 구현이 C ++ 표준에 의해 지정되지 않습니다. 결과적으로 두 개의 부동 소수점 비 유형 인수가 실제로 일치하는지 결정하기가 어렵습니다.
template <float f> void foo () ;
void bar () {
foo< (1.0/3.0) > ();
foo< (7.0/21.0) > ();
}
이러한 표현은 반드시 동일한 "비트 패턴"을 생성하는 것은 아니므로이를 다루기위한 특별한 표현 없이는 동일한 전문화를 사용했다고 보장 할 수 없습니다.
실제로 float 리터럴을 템플릿 매개 변수로 사용할 수 없습니다. 표준의 섹션 14.1 ( "비 유형 템플릿 매개 변수는 다음 (선택적으로 cv-qualified) 유형 중 하나를 가져야한다 ...") 참조 .
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;
자체 클래스의 매개 변수를 constexprs로 래핑합니다. 사실상 이것은 float 세트로 클래스를 매개 변수화하므로 트레이 트와 유사합니다.
class MyParameters{
public:
static constexpr float Kd =1.0f;
static constexpr float Ki =1.0f;
static constexpr float Kp =1.0f;
};
그런 다음 클래스 유형을 매개 변수로 사용하는 템플릿을 만듭니다.
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 ...
};
그런 다음 그렇게 사용하십시오 ...
int main (){
PidController<float, MyParameters> controller;
...
...
}
This allows the compiler to guarantee that only a single instance of the code is created for each template instantiation with the same parameter pack. That gets around all the issues and you are able to use floats and doubles as constexpr inside the templated class.
If you are ok to have a fixed default per type you can create a type to define it as a constant and specialize it as needed.
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;
};
If you have C++11 you can use constexpr when defining the default value. With C++14, MyTypeDefault can be a template variable which is a bit cleaner syntactically.
//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>;
};
You can always fake it...
#include <iostream>
template <int NUM, int DEN>
struct Float
{
static constexpr float value() { return (float)NUM / (float)DEN; }
static constexpr float VALUE = value();
};
template <class GRAD, class CONST>
struct LinearFunc
{
static float func(float x) { return GRAD::VALUE*x + CONST::VALUE; }
};
int main()
{
// Y = 0.333 x + 0.2
// x=2, y=0.866
std::cout << " func(2) = "
<< LinearFunc<Float<1,3>, Float<1,5> > ::func(2) << std::endl;
}
Ref: http://code-slim-jim.blogspot.jp/2013/06/c11-no-floats-in-templates-wtf.html
If you don't need the double to be a compile-time constant, you can pass it in as a pointer:
#include <iostream>
extern const double kMyDouble = 0.1;;
template <const double* MyDouble>
void writeDouble() {
std::cout << *MyDouble << std::endl;
}
int main()
{
writeDouble<&kMyDouble>();
return 0;
}
If you only want to represent a fixed precision, then you can use a technique like this to convert a float parameter into an int.
For example an array with a growth factor of 1.75 could be created as follows assuming 2 digits of precision (divide by 100).
template <typename _Kind_, int _Factor_=175>
class Array
{
public:
static const float Factor;
_Kind_ * Data;
int Size;
// ...
void Resize()
{
_Kind_ * data = new _Kind_[(Size*Factor)+1];
// ...
}
}
template<typename _Kind_, int _Factor_>
const float Array<_kind_,_Factor_>::Factor = _Factor_/100;
If you dont like the representation of 1.75 as 175 in the template argument list then you could always wrap it in some macro.
#define FloatToIntPrecision(f,p) (f*(10^p))
template <typename _Kind_, int _Factor_=FloatToIntPrecision(1.75,2)>
// ...
The other answers give good reasons why you probably do not want floating point template parameters, but the real deal braker IMO is that equality using '==' and bitwise equality are not the same:
-0.0 == 0.0
, but0.0
and-0.0
are not bitwise equalNAN != NAN
Neither kind of equality is a good cancidate for type equality: Of course, point 2. makes using ==
invalid for determining type equality. One could use bitwise equality instead, but then x != y
does not imply that MyClass<x>
and MyClass<y>
are different types (by 2.), which would be rather strange.
참고URL : https://stackoverflow.com/questions/2183087/why-cant-i-use-float-value-as-a-template-parameter
'programing tip' 카테고리의 다른 글
Map Reduce Programming의 감속기에서 셔플 링 및 정렬 단계의 목적은 무엇입니까? (0) | 2020.08.13 |
---|---|
진행 중입니다. (0) | 2020.08.13 |
잘못된 형식의 숫자 값이 있습니다. (0) | 2020.08.13 |
명령 줄에서 JAR 파일을 실행하고 클래스 경로를 지정합니다. (0) | 2020.08.13 |
Maven을 사용하지 않고 Spring Framework jar를 어디에서 다운로드 할 수 있습니까? (0) | 2020.08.13 |