3

I'm currently start using boost::program_options for parsing command line options as well as configuration files.

Is it possible to use own template classes as option arguments? That means, something like

#include <iostream>
#include "boost/program_options.hpp"

namespace po = boost::program_options;

template <typename T>
class MyClass
{
private:
    T*   m_data;
    size_t m_size;
public:
    MyClass( size_t size) : m_size(size) { m_data = new T[size]; }
    ~MyClass() { delete[] m_data; }
    T get( size_t i ) { return m_data[i]; }
    void set( size_t i, T value ) { m_data[i] = value; }
};

int main (int argc, const char * argv[])
{    
    po::options_description generic("General options");
    generic.add_options() ("myclass", po::value< MyClass<int>(2) >(), 
                           "Read MyClass");
    return 0;
}

Trying to compile this I get an Semantic Issue (No matching function for call to 'value'). I guess I need to provide some casting to an generalized type but I have no real idea.

Can anybody help? Thanks

Aeon512

Aeon512
  • 33
  • 2

2 Answers2

2

I wouldn't know if boost::program_options allows the use-case you are trying, but the error you are getting is because your are trying to pass an object as a template type to po::value<>. If the size is known at compile-time, you could have the size be passed in as a template parameter.

template< typename T, size_t size >
class MyClass {
  T m_data[size];
public:
  // ...
};

And then use it like so:

po::value< MyClass<int, 2> >()

You should also look into using Boost.Array instead that I guess fulfills what you are trying to implement.

Oskar N.
  • 8,427
  • 2
  • 23
  • 21
2

I would write it like this:

MyClass<int> mine(2);
generic.add_options() ("myclass", po::value(&mine), "Read MyClass");

Then all that needs to be done is to define an input stream operator like this:

std::istream& operator >>(std::istream& source, MyClass& target);

Then Boost Program Options will invoke this stream operator when the myclass option is used, and your object will be automatically populated according to that operator's implementation, rather than having to later call one of the Program Options functions to extract the value.

If you don't prefer the above syntax, something like should work too:

generic.add_options() ("myclass", po::value<MyClass<int> >()->default_value(MyClass<int>(2)), "Read MyClass");

This way you would be creating the instance of your class directly with your desired constructor argument outside of the template part where runtime behavior isn't allowed. I do not prefer this way because it's verbose and you end up needing to call more functions later to convert the value.

John Zwinck
  • 239,568
  • 38
  • 324
  • 436