c++c++11templates

C++ class member's specialization with nontype arguments


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;
}

Solution

  • 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;
    }
    

    See it online