0
votes

I have a problem in wrapping a template class in a non-template one;

I'm trying to make this code work:

my_class.hpp

#ifndef MY_CLASS_HPP
#define MY_CLASS_HPP

#include <vector>
#include <iostream>

class VectorPrinter {

private:

  template<class value_type>
  static std::vector<value_type> vec;

public:

  template<class value_type>
  VectorPrinter(const std::vector<value_type>& vec_)
  {
    vec = vec_
    for (std::size_t i = 0; i<vec.size(); ++i)
      std::cout << vec[i] << std::endl;
  }

};

#endif /* MY_CLASS_HPP */

main.cpp

#include "my_class.hpp"
#include <string>

int main() {

std::vector<int> v1{1, 2, 3, 4, 5};
std::vector<std::string> v2{"Hello", "world", "!"};
std::vector<double> v3{2.5, 7.3, -5.1};

VectorPrinter vp1(v1);
VectorPrinter vp2(v2);
VectorPrinter vp3(v3);

return 0;

}

I get the following error message while trying to compile (I tried -std=c++11, -std=c++14, -std=c++17: no difference; no difference neither switching from g++ to clang):

./my_class.hpp:19:5: error: cannot refer to variable template 'vec' without a template argument list

Now: my goal is to circumvent defining VectorPrinter as a template class or, alternatively, avoid specifying the template argument in the case VectorPrinter cannot be non-template; so my problem reside within the scope of either variable template or template argument deduction.

This is just a test for my thesis project; what I need to achieve, at the end, is being able to define a template library for RNG and to encapsulate these classes in more complex ones which perform Direct Simulation Monte Carlo. So, at the end I would like something like:

template <class engineType>
class RngObject {
   // ...
};
class Ensemble {
   private:
      template<class engineType> RngObject<engineType> rng;
   // ...
};

It would be quite boring having to define each and every class that encapsulate a RNG as template; moreover, I am asked to avoid using dynamic time polymorphism, at leat at this stage.

I hope someone can provide me some useful suggestion. Thanks

2
Why are you making a deep copy of the vector to print?Mooing Duck
@MooingDuck it's just a test; i actually, in my project I would use reference to RNG objects, insteadMichele Pellegrino

2 Answers

3
votes

The error message says quite clearly what you have to do: Specify the template argument for vec.

  template<class value_type>
  VectorPrinter(const std::vector<value_type>& vec_)
  {
    // Using a reference here so we don't have to type all this again and again.
    auto& v = vec<value_type>;
    v = vec_;
    for (std::size_t i = 0; i < v.size(); ++i)
      std::cout << v[i] << std::endl;
  }

You'll also have to provide the definition for your variable template:

template<class value_type>
std::vector<value_type> VectorPrinter::vec;

Together this should give you what you're asking for: https://godbolt.org/z/gVFvFw
(Whether this is a good design for your use case is a different question).

1
votes

I have certain doubts if you are on the right way; you get forced to use static members this way, but now all instances will compete for this single common member (well, only all those that use the same template type, of course). This could lead to race conditions among those objects with same template type, especially in a multi-threaded environment.

A true template class would allow to have non-static members, which might be safer and thus preferable.

If you opted for template variables just for not having to repeat the template arguments on object creation, then there's good news: Since C++17, you can let deduce class template arguments from constructor. So if you do make your class a template:

template<class value_type>
class VectorPrinter { /* ... */ };

you still can define your objects without having to specify the template arguments:

VectorPrinter vp1(v1); // fine with above template, too - since C++17

but don't rely on static members.

If you wanted to place multiple VectorPrinters (template version) of different types into a common container, though, then you'd need to introduce a common base class. So in such a scenario, you have the choice: No static variables (especially: no varying number of), but polymorphism, or the other way round. I have my clear personal preference (doesn't mean I'd refuse the other approach, if proved superior in a specific scenario), but you'll have to weigh up yourself...