I need to define a class with nontype template parameters and specialize one of its function member's. The code below is a reasonable simplification of what I need to do (we can assume this is c++11 but I don't think the C++ standard is the issue here).
template <class T, std::size_t LIMIT=100>
struct A {
std::array<T,LIMIT> array;
void print (T value) {
std::cout << LIMIT << std::endl;
std::cout << value << std::endl;
}
};
template<>
void A<float>::print(float value) {
std::cout << LIMIT << std::endl;
std::cout << value*10.0 << std::endl;
}
int main (int argc, const char** argv) {
A<float> a;
a.print(23.3);
}
When I compile it (g++ 9.4.), I get this error:
test.cpp: In member function ‘void A<T, LIMIT>::print(T) [with T = float; long unsigned int LIMIT = 100]’:
test.cpp:20:16: error: ‘LIMIT’ was not declared in this scope
20 | std::cout << LIMIT << std::endl;
| ^~~~~
which is quite surprising since it seems to me that the compile knows very well what LIMIT is ("long unsigned int LIMIT = 100").
If I implement the function this way:
template<>
void A<float, std::size_t LIMIT=100>::print(float value) {
std::cout << LIMIT << std::endl;
std::cout << value*10.0 << std::endl;
}
I instead get this other error:
test.cpp:18:36: error: template argument 2 is invalid
18 | void A<float, std::size_t LIMIT=100>::print(float value) {
| ^
test.cpp:18:56: error: ‘print’ is not a template function
18 | void A<float, std::size_t LIMIT=100>::print(float value) {
|
I suspect there are some limitations on function members specializations and nontype parameters that I am unaware of.
PS: this is an example of some code that will run in an embedded system, so I actually need nontype params, that's non-negotiable.
I tried without success
template<>
void A<float>::print(float value) {
std::cout << LIMIT << std::endl;
std::cout << value*10.0 << std::endl;
}
template<>
void A<float, std::size_t LIMIT>::print(float value) {
std::cout << LIMIT << std::endl;
std::cout << value*10.0 << std::endl;
}
and
template<>
void A<float, std::size_t LIMIT=100>::print(float value) {
std::cout << LIMIT << std::endl;
std::cout << value*10.0 << std::endl;
}
LIMIT
is only defined within context of definition of A
class template, but you are defining a function out of that context. Same way you cannot refer to T
anywhere outside of class template definition.
The usual solution for types is to provide a name alias
using value_type = T;
so for non-type template parameter I'd do a simple static constexpr value in class:
template <class T, std::size_t LIMIT=100>
struct A {
constexpr static std::size_t limit_v = LIMIT;
//...
};
// and then in definition you can do
template<>
void A<float>::print(float value) {
std::cout << limit_v << std::endl;
std::cout << value*10.0 << std::endl;
}