what's the right way to export template function from c++ into python using boost.python? Here is the code:
template<typename T>
T getValue(const std::string &key, const T &defaultValue = T()) {}
// Export into some python class:
class_<ConfigManager>(...)
.def("GetValue", getValue<int>)
.def("GetValue", getValue<float>)
.def("GetValue", getValue<std::string>);
And usage:
print GetValue("width")
Boost.Python.ArgumentError: Python argument types in
GetValue(ConfigManager, str)
did not match C++ signature:
GetValue(ConfigManager {lvalue}, std::string, int)
What's wrong?
You should read the relevant Boost documentation regarding default arguments. I'll summarize below.
The problem here is that default arguments are used when calling functions in C++. Get rid of them and you'll see the problem from Python's perspective:
// this function *must* be called with two parameters
template<typename T>
T getValue(const std::string &key, const T &defaultValue) {}
class_<ConfigManager>(...)
.def("GetValue", getValue<int>) // two arguments!
.def("GetValue", getValue<float>) // Python has no idea about the defaults,
.def("GetValue", getValue<std::string>); // they are a C++ feature for calling
The fundamental issue is that function types don't carry default argument information. So how can we simulate it? Essentially, by overloading:
template<typename T>
T getValue(const std::string &key, const T &defaultValue) {}
template<typename T>
T getValueDefault(const std::string &key)
{
// default available in C++,
// transitively available in Python
return getValue(key);
}
class_<ConfigManager>(...)
.def("GetValue", getValue<int>) // two arguments
.def("GetValue", getValueDefault<int>) // one argument
// and so on
A maintenance hassle. Luckily, Boost makes this easy:
template<typename T>
T getValue(const std::string &key, const T &defaultValue) {}
// creates utility class x, which creates overloads of function y,
// with argument count as low as a and as high as b:
// BOOST_PYTHON_FUNCTION_OVERLOADS(x, y, a, b);
BOOST_PYTHON_FUNCTION_OVERLOADS(getValueIntOverloads, getValue<int>, 1, 2);
class_<ConfigManager>(...)
.def("GetValue", getValue<int>, getValueIntOverloads()) // one or two arguments
// and so on
The macro also exists for class members. This is in the documentation, if any of it is unclear.
You can also add another template for your class so that you don't have to write/instantiate for each int/float type.
template<typename LinksT>
class Base {
public:
virtual ~Base() {}
virtual Base* x() = 0;
};
#include <boost/python.hpp>
using namespace boost::python;
template<typename LinksT>
class BaseWrap : public Base<LinksT>, public wrapper<Base<LinksT> > {
public:
virtual Base<LinksT>* x() { return this->get_override("x")(); }
};
template<typename LinksT>
void export_virtualfunction()
{
class_<BaseWrap<LinksT>, boost::noncopyable>("Base", no_init)
.def("x", pure_virtual(&Base<LinksT>::x), return_internal_reference<>())
;
}
BOOST_PYTHON_MODULE(test_template_python)
{
export_virtualfunction<int>();
}
Related
I have an algorithm (not preseted here) which takes as input different parameters (int, float, vectors).
My idea of design was to have an container which holds all these differents parameters.
To achive this, I have a base class Parameter and a derivated template class TypeParameter.
These parameters will be holded in a container.
The design is presented below:
#pragma once
#include <utility>
#include <memory>
#include <string>
#include <vector>
namespace parameter
{
/*
Interface for parameter
*/
class Parameter
{
public:
Parameter() {}
Parameter(std::string param_name) : name(param_name) {}
Parameter(const Parameter&& other) noexcept : name(std::move(other.name)) {}
virtual ~Parameter() {}
inline const std::string get_name() { return name; }
private:
std::string name;
};
/*
*/
template<class T>
class TypeParameter
: public Parameter
{
public:
TypeParameter(std::string param_name, T new_value) : Parameter(param_name), value(new_value) {}
TypeParameter(const TypeParameter&& other) noexcept : Parameter(std::move(other)), value(std::move(other.T)) {}
inline const T get_value() { return value; }
private:
T value;
};
/*
Container for parameters
*/
class ParameterSet
{
public:
ParameterSet() {}
void add(std::unique_ptr<Parameter> param) { data.push_back(std::move(param)); }
private:
std::vector <std::unique_ptr<Parameter>> data;
};
} //namespace parameter
The main is:
#include <iostream>
#include <string>
#include "Parameter.h"
using parameter::TypeParameter;
using parameter::Parameter;
using parameter::ParameterSet;
void foo(std::unique_ptr<Parameter> p)
{
std::cout << p->get_value(); // ERROR
}
int main(int argc, char *argv[])
{
TypeParameter<int> *iparam = new TypeParameter<int>("ee", 3);
std::unique_ptr<Parameter> p = std::make_unique <TypeParameter<int>>("foo", 3);
foo(std::move(p));
ParameterSet param_set;
param_set.add(std::unique_ptr<Parameter>(iparam));
param_set.add(std::move(p));
getchar();
}
My problem is I cannot get the value without a cast.
Hence, my question is how do I cast the unique_ptr from a Parameter class to derived TypeParameter.
Is there another way to design the container?
Thanks a lot!
You don't have to reinvent the wheel. There are a couple of classes you can use from the standard library:
std::variant.
As suggested by the comments, variant is a type-safe union of a pre-defined set of data types, which you put in the templates argument of variant.
For example, a std::variant<int,float,double> can hold any value of type int, float, or double, but nothing else.
To use the stored value, you can either use the visitor pattern with the std::visit() function. Other functions allow you to know which of the preset types is stored in the variable (index()) and to extract the value from it (using get()). If you try to extract the value of the wrong type, the get() function throws an exception
std::any
is another utility that can hold different data types. As opposed to variant, you don't have to know the types at compile-time. Basically, it stores a void* to the data with a typeinfo to remember its original type. You can then use any_cast to cast the variable back to its original type. Just like variant, an exception is thrown when trying to cast to the wrong type.
These two classes are available in C++ 17. If these features are not available to you, they were also included in boost (respectively boost:variant and boost:any)
You can store the set of values in a standard library container, e.g. in a std::vector<std::variant<int,float,double>> or a std::vector<std::any>>.
Alternative to std::variant/std::any is the old way polymorphism:
class Parameter
{
public:
Parameter(const std::string& param_name) : name(param_name) {}
virtual ~Parameter() = default;
const std::string& get_name() const { return name; }
virtual void printValue() const = 0;
// Other virtual methods
private:
std::string name;
};
template<class T>
class TypeParameter : public Parameter
{
public:
TypeParameter(const std::string& name, const T& t) : Parameter(name), value(t) {}
// Non virtual method when we don't access it by base class.
const T& get_value() const { return value; }
void printValue() const { std::cout << value; }
private:
T value;
};
And then your
void foo(const Parameter& p)
{
std::cout << p.get_value(); // ERROR
}
becomes
void foo(const Parameter& p)
{
p.print();
}
If you don't want to add many virtual methods to Parameter, then Visitor pattern can help, but then you have to know each derived types.
Working on a command line parser for myself. I knew immediately that I was going to have trouble with this construct and hoping someone could provide suggestions for a work around.
I want to store the argument list of parameters (based off a template) in a vector that will possibly contain a variety of different data types. But from my understanding, you have to define the vector<template<type>> statically. Is there a way to except multiple types?
Here is an example of what I mean:
#include <vector>
#include <memory>
namespace clparser
{
class CommandLine {
private:
std::vector<Parameter<AnyType??>*> ArgumentList;
public:
void Add(Parameter<AnyType??>* Parameter) { ArgumentList.push_back(Parameter); }
};
template<typename T>
class Parameter {
private:
const char *ShortOption;
const char *LongOption;
const char *Description;
const bool RequiredField;
const char *DefaultValue;
public:
Parameter(const char *ShortOption, const char *LongOption, const char *Description, const bool RequiredField, const char *DefaultValue)
: ShortOption(ShortOption), LongOption(LongOption), Description(Description), RequiredField(RequiredField), DefaultValue(DefaultValue)
{
}
};
}
If you can accept a C++11 solution, I propose you a iper-simplified version from my command line parser. Hoping that can be of inspiration for you.
The idea behind my solution is the use of base/derived polymorphism: a pure virtual class optBase that is a base for a set of template classes dedicated to options (in the following example, only class opt; but there are other three in my parser).
Then the (not template) class yData contain a std::unique_ptr<optBase> (if you use a simple pointer to optBase you can compile in C++98 too, I suppose; but I suggest the use of C++11 or newer).
class yData correspond (roughly) to your tou your class Parameter but (here is the trick) isn't a template class; contain a base pointer to a template class.
My class yarg correspond to your class clparser and my std::map<int, yData> idMap correspond (roughly) to your std::vector<Parameter<AnyType??>*> ArgumentList.
To feed idMap, I've developed a set of template method (one for every derived from optbase classes); in the following example you can see a iper-semplified version of one of them: addOpt() (corresponding, roughly, to your Add()).
In the following example you can see a little main() with a couple of uses for addOpt(): the first for a int parameter and the second for a double parameter (important (and weak point of my solution): the returned value must be saved in a reference variable, not in a simple variable).
#include <map>
#include <memory>
class optBase
{
public:
// some pure virtual methods
};
template <typename X>
class opt : public optBase
{
private:
X val { };
// ...
public:
opt ()
{ }
opt (X const & v0)
: val { v0 } // ...
{ }
X const & getVal () const
{ return val; }
X & getVal ()
{ return val; }
// ...
};
// other optBase derived classes (for flags, containers of values, etc)
class yData
{
private:
// ...
std::unique_ptr<optBase> optB;
public:
yData (/* other arguments */ std::unique_ptr<optBase> optB0)
: /* something else */ optB { std::move(optB0) }
{ }
// ...
std::unique_ptr<optBase> const & getPnt () const
{ return optB; }
};
class yarg
{
private:
// ...
std::map<int, yData> idMap;
// ...
public:
// ...
template <typename T>
T & addOpt (/* other arguments */ T const & def = T())
{
int id { /* some value */ };
opt<T> * optP { nullptr };
// ...&
idMap.emplace(std::piecewise_construct,
std::forward_as_tuple(id),
std::forward_as_tuple(/* other arguments */
std::unique_ptr<optBase>(optP = new opt<T>(def))));
return optP->getVal();
}
};
int main ()
{
yarg y;
// important: use a *reference*
auto & pi = y.addOpt(3); // pi is a int
auto & pd = y.addOpt(3.0); // pd is a double
static_assert(std::is_same<decltype(pi), int &>::value, "!");
static_assert(std::is_same<decltype(pd), double &>::value, "!!");
}
Suppose I have this class :
class Component1;
class Component2;
// many different Components
class Component42;
class MyClass
{
public:
MyClass(void) {};
std::list<Component1> component1List;
std::list<Component2> component2List;
// one list by component
std::list<Component42> component42List;
};
I would like to create a function with the following signature:
template<class T> void addElement(T component);
It should do the following:
if component is of type Component1, add it to Component1List
if component is of type Component2, add it to Component2List, etc.
Is it possible? What's a good way to do this?
I can obtain the same behaviour with a function like :
template<class T> void addElement(int componentType, T component);
but I'd rather not have to specify the componentType like this : it's useless information and it open the door to possible errors (if componentType doesn't represent the type of component).
std::tuple to the rescue.
changelog:
use std::decay_t
added the variadic argument form
add_component() now returns a reference to this to allow call-chaining.
#include <iostream>
#include <list>
#include <utility>
#include <type_traits>
#include <tuple>
class Component1 {};
class Component2 {};
struct Component3 {
Component3() {}
};
// many different Components
template<class...ComponentTypes>
class MyClassImpl
{
template<class Component> using list_of = std::list<Component>;
public:
using all_lists_type =
std::tuple<
list_of<ComponentTypes> ...
>;
// add a single component
template<class Component>
MyClassImpl& add_component(Component&& c)
{
list_for<Component>().push_back(std::forward<Component>(c));
return *this;
}
// add any number of components
template<class...Components>
MyClassImpl& add_components(Components&&... c)
{
using expand = int[];
void(expand { 0, (void(add_component(std::forward<Components>(c))), 0)... });
return *this;
}
template<class Component>
auto& list_for()
{
using component_type = std::decay_t<Component>;
return std::get<list_of<component_type>>(_lists);
}
template<class Component>
const auto& list_for() const
{
using component_type = std::decay_t<Component>;
return std::get<list_of<component_type>>(_lists);
}
private:
all_lists_type _lists;
};
using MyClass = MyClassImpl<Component1, Component2, Component3>;
int main()
{
MyClass c;
c.add_component(Component1());
c.add_component(Component2());
const Component3 c3;
c.add_component(c3);
c.add_components(Component1(),
Component2(),
Component3()).add_components(Component3()).add_components(Component1(),
Component2());
std::cout << c.list_for<Component1>().size() << std::endl;
return 0;
}
The most straightforward variant is to simply not use templates but to overload the addElement() function:
void addElement(Component1 element)
{
this->element1List.push_back(element);
}
void addElement(Component2 element)
{
this->element2List.push_back(element);
}
// ... etc
However, this might get tedious if you have many of these (and you don't just have addElement(), I guess). Using a macro to generate the code for each type could still do the job with reasonable effort.
If you really want to use templates, you could use a template function and specialize the template function for each type. Still, this doesn't reduce the amount of code repetition when compared with the above approach. Also, you could still reduce it using macros to generate the code.
However, there's hope for doing this in a generic way. Firstly, let's create a type that holds the list:
template<typename T>
struct ComponentContainer
{
list<T> componentList;
};
Now, the derived class just inherits from this class and uses C++ type system to locate the correct container baseclass:
class MyClass:
ComponentContainer<Component1>,
ComponentContainer<Component2>,
ComponentContainer<Component3>
{
public:
template<typename T>
void addElement(T value)
{
ComponentContainer<T>& container = *this;
container.componentList.push_back(value);
}
}
Notes here:
This uses private inheritance, which is very similar to the containment you originally used.
Even though ComponentContainer is a baseclass, it doesn't have any virtual functions and not even a virtual destructor. Yes, this is dangerous and should be documented clearly. I wouldn't add a virtual destructor though, because of the overhead it has and because it shouldn't be needed.
You could drop the intermediate container altogether and derive from list<T>, too. I didn't because it will make all of list's memberfunctions available in class MyClass (even if not publicly), which might be confusing.
You can't put the addElement() function into the base class template to avoid the template in the derived class. The simple reason is that the different baseclasses are scanned in order for a addElement() function and only then overload resolution is performed. The compiler will only find the addElement() in the first baseclass therefore.
This is a plain C++98 solution, for C++11 I'd look at the type-based tuple lookup solutions suggested by Jens and Richard.
If there are not too many classes you could go with overloading. A template-based solution could be done with type-based lookup for tuples:
class MyClass {
public:
template<typename T> void addElement(T&& x) {
auto& l = std::get<std::list<T>>(lists);
l.insert( std::forward<T>(x) );
}
private:
std::tuple< std::list<Component1>, std::list<Component2> > lists;
};
If you don't know in advance the types you will need storing when instantiating the multi-container an option is to hide the types and using type_index to keep a map of lists:
struct Container {
struct Entry {
void *list;
std::function<void *(void*)> copier;
std::function<void(void *)> deleter;
};
std::map<std::type_index, Entry> entries;
template<typename T>
std::list<T>& list() {
Entry& e = entries[std::type_index(typeid(T))];
if (!e.list) {
e.list = new std::list<T>;
e.deleter = [](void *list){ delete ((std::list<T> *)list); };
e.copier = [](void *list){ return new std::list<T>(*((std::list<T> *)list)); };
}
return *((std::list<T> *)e.list);
}
~Container() {
for (auto& i : entries) i.second.deleter(i.second.list);
}
Container(const Container& other) {
// Not exception safe... se note
for (auto& i : other.entries) {
entries[i.first] = { i.second.copier(i.second.list),
i.second.copier,
i.second.deleter };
}
};
void swap(Container& other) { std::swap(entries, other.entries); }
Container& operator=(const Container& other) {
Container(other).swap(*this);
return *this;
};
Container() { }
};
that can be used as:
Container c;
c.list<int>().push_back(10);
c.list<int>().push_back(20);
c.list<double>().push_back(3.14);
NOTE: the copy constructor as written now is not exception safe because in case a copier throws (because of an out of memory or because a copy constructor of an element inside a list throws) the already allocated lists will not be deallocated.
void addElement(Component1 component) {
componentList1.insert(component);
}
void addElement(Component2 component) {
componentList2.insert(component);
}
I'm using a pair type:
typedef std::pair<int, std::string> Nomnom;
Example places it's used:
void DoIt(const Nomnom &toNom) {
...
}
void DoItAgain(const Nomnom &toNomAgain) {
...
}
In my case it makes sense to offer a default value for the pair if it isn't specified. That is, I want to be able to do this:
DoIt("Thisisit");
DoItAgain("Thisisit");
and have it be equivalent to this:
DoIt(NomNom(0, "Thisisit"));
DoItAgain(NomNom(0, "Thisisit"));
I want to do this without defining two variants every time a Nomnom is used.
Is there any way to accomplish this short of defining a class for Nomnom instead of the typedef, providing a one-arg constructor, and then providing the zero-arg and two-arg constructors that call the std::pair constructors?
You cannot easily add your own constructor to std::pair (inheriting from it isn't really an option).
But you can provide a small function to construct it and overload it accordingly:
Nomnom nomnom(const std::string& s) { return Nomnom(-1, s); }
Nomnom nomnom(int i) { return Nomnom(i, ""); }
You could also overload DoIt and DoItAgain and forward on a common implementation.
void DoIt(const Nomnom& n) { /* ... */ }
void DoIt(int i) { DoIt(Nomnom(i, "")); }
ORIGINAL QUESTION
Is there any way to accomplish this short of defining a class for Nomnom instead, providing a one-arg constructor, and then providing the zero-arg and two-arg constructors that call the std::pair constructors?
You could have more constructor overloads as
ClassNoms() : one(std::make_pair(-1,"") {}
ClassNoms(int id) : one(std::make_pair(id,"") {}
ClassNoms(const std::string& name) : one(std::make_pair(-1,name) {}
ClassNoms(int id, const std::string& name) : one(std::make_pair(id,name) {}
UPDATE:
Is there any way to accomplish this short of defining a class for Nomnom instead of the typedef, providing a one-arg constructor, and then providing the zero-arg and two-arg constructors that call the std::pair constructors?
typedef std::pair<int, std::string> Nomnom;
You can't provide a default constructor for your typedef'd NomNom, because std::pair<> doesn't provide one. To achieve this, you'll need to either inherit a class NomNom from std::pair<>, or IMHO better provide a wrapper for it, and use this one:
template<typename First,typename Second>
struct DefaultValuedPair {
std::pair<First,Second> value;
First& first;
Second& second;
DefaultValuedPair
( const First& first = First()
, const Second& second = Second()
)
: value(std::make_pair(first,second))
, first(value.first)
, second(value.second) {}
DefaultValuedPair(const std::pair<First,Second>& rhs)
: value(rhs)
, first(value.first)
, second(value.second) {}
// Add more implicit type conversions for std::pair<First,Second>
// as necessary ...
};
And have
typedef DefaultValuedPair<int, std::string> Nomnom;
You could have a function that acts like a constructor, but it can't be named and called as pure equivalent for a NomNom (declared) type, and this wouldn't give any advantage over using std::make_pair().
The proposed wrapper solution might have a huge impact on considerations of refactoring already existing code that uses NomNom, and should work seamlessly with such. As mentioned, just replacing/disguising std::make_pair per se, makes no sense IMHO.
If you're using C++11, you can just inherit the constructors from pair with using. I think this is the cleanest solution to your problem.
Is there a reason (besides not wanting to re-implement std::pair's constructors) you don't want to inherit from std::pair?
#include <utility>
#include <string>
#include <iostream>
/**
* Nomnom is just a std::pair with a customized constructor.
*/
class Nomnom : public std::pair <int, std::string> {
typedef std::pair<int, std::string> parent_type; // For convenience
public:
using parent_type::parent_type; // Inherit Pair's constructors
Nomnom (std::string S) : parent_type(0, S) {} // And add our own
Nomnom (char const * S) : parent_type(0, S) {} // Handle C strings...
};
/**
* Show that we can just use Nomnom as a std::pair...
*/
template <class FIRST, class SECOND>
std::ostream & operator<< (std::ostream & out, std::pair <FIRST, SECOND> const & print_me) {
return out << print_me.first << ", " << print_me.second << '\n';
}
/**
* Use this to test initizlization while passing to a method
*/
void foo (Nomnom const & print_me) {
std::cout << print_me;
}
int main (void) {
std::cout << Nomnom("Hello!");
std::cout << Nomnom(5, "World!");
foo ("Mouse!");
return 0;
}
I have a map which represents a configuration. It's a map of std::string and boost::any.
This map is initialized at the start and I'd like the user to be able to override these options on the command line.
What I'd love to do is build the program options from this map using the options_description::add_option() method. However, it takes a template argument po::value<> whereas all I have is boost::any.
So far, I just have the shell of the code. m_Config represents my configuration class, and getTuples() returns a std::map<std::string, Tuple>. TuplePair is a typedef of std::pair<std::string, Tuple> and the Tuple contains the boost::any I am interested in.
po::options_description desc;
std::for_each(m_Config.getTuples().begin(),
m_Config.getTuples().end(),
[&desc](const TuplePair& _pair)
{
// what goes here? :)
// desc.add_options() ( _pair.first, po::value<???>, "");
});
Is there a way to build it this way, or do I need to resort to doing it myself?
Thanks in advance!
boost::any is not applicable to your problem. It performs the most basic form of type erasure: storage and (type-safe) retrieval, and that's it. As you've seen, no other operations can be performed. As jhasse points out, you could just test every type you want to support, but this is a maintenance nightmare.
Better would be to expand upon the idea boost::any uses. Unfortunately this requires a bit of boiler-plate code. If you'd like to try it, there's a new Boost library being discussed right now on the mailing list (titled "[boost] RFC: type erasure") that is essentially a generalized type erasure utility: you define the operations you'd like your erased type to support, and it generates the proper utility type. (It can simulate boost::any, for example, by requiring the erased type be copy-constructible and type-safe, and can simulate boost::function<> by additionally requiring the type be callable.)
Aside from that, though, your best option is probably to write such a type yourself. I'll do it for you:
#include <boost/program_options.hpp>
#include <typeinfo>
#include <stdexcept>
namespace po = boost::program_options;
class any_option
{
public:
any_option() :
mContent(0) // no content
{}
template <typename T>
any_option(const T& value) :
mContent(new holder<T>(value))
{
// above is where the erasure happens,
// holder<T> inherits from our non-template
// base class, which will make virtual calls
// to the actual implementation; see below
}
any_option(const any_option& other) :
mContent(other.empty() ? 0 : other.mContent->clone())
{
// note we need an explicit clone method to copy,
// since with an erased type it's impossible
}
any_option& operator=(any_option other)
{
// copy-and-swap idiom is short and sweet
swap(*this, other);
return *this;
}
~any_option()
{
// delete our content when we're done
delete mContent;
}
bool empty() const
{
return !mContent;
}
friend void swap(any_option& first, any_option& second)
{
std::swap(first.mContent, second.mContent);
}
// now we define the interface we'd like to support through erasure:
// getting the data out if we know the type will be useful,
// just like boost::any. (defined as friend free-function)
template <typename T>
friend T* any_option_cast(any_option*);
// and the ability to query the type
const std::type_info& type() const
{
return mContent->type(); // call actual function
}
// we also want to be able to call options_description::add_option(),
// so we add a function that will do so (through a virtual call)
void add_option(po::options_description desc, const char* name)
{
mContent->add_option(desc, name); // call actual function
}
private:
// done with the interface, now we define the non-template base class,
// which has virtual functions where we need type-erased functionality
class placeholder
{
public:
virtual ~placeholder()
{
// allow deletion through base with virtual destructor
}
// the interface needed to support any_option operations:
// need to be able to clone the stored value
virtual placeholder* clone() const = 0;
// need to be able to test the stored type, for safe casts
virtual const std::type_info& type() const = 0;
// and need to be able to perform add_option with type info
virtual void add_option(po::options_description desc,
const char* name) = 0;
};
// and the template derived class, which will support the interface
template <typename T>
class holder : public placeholder
{
public:
holder(const T& value) :
mValue(value)
{}
// implement the required interface:
placeholder* clone() const
{
return new holder<T>(mValue);
}
const std::type_info& type() const
{
return typeid(mValue);
}
void add_option(po::options_description desc, const char* name)
{
desc.add_options()(name, po::value<T>(), "");
}
// finally, we have a direct value accessor
T& value()
{
return mValue;
}
private:
T mValue;
// noncopyable, use cloning interface
holder(const holder&);
holder& operator=(const holder&);
};
// finally, we store a pointer to the base class
placeholder* mContent;
};
class bad_any_option_cast :
public std::bad_cast
{
public:
const char* what() const throw()
{
return "bad_any_option_cast: failed conversion";
}
};
template <typename T>
T* any_option_cast(any_option* anyOption)
{
typedef any_option::holder<T> holder;
return anyOption.type() == typeid(T) ?
&static_cast<holder*>(anyOption.mContent)->value() : 0;
}
template <typename T>
const T* any_option_cast(const any_option* anyOption)
{
// none of the operations in non-const any_option_cast
// are mutating, so this is safe and simple (constness
// is restored to the return value automatically)
return any_option_cast<T>(const_cast<any_option*>(anyOption));
}
template <typename T>
T& any_option_cast(any_option& anyOption)
{
T* result = any_option_cast(&anyOption);
if (!result)
throw bad_any_option_cast();
return *result;
}
template <typename T>
const T& any_option_cast(const any_option& anyOption)
{
return any_option_cast<T>(const_cast<any_option&>(anyOption));
}
// NOTE: My casting operator has slightly different use than
// that of boost::any. Namely, it automatically returns a reference
// to the stored value, so you don't need to (and cannot) specify it.
// If you liked the old way, feel free to peek into their source.
#include <boost/foreach.hpp>
#include <map>
int main()
{
// (it's a good exercise to step through this with
// a debugger to see how it all comes together)
typedef std::map<std::string, any_option> map_type;
typedef map_type::value_type pair_type;
map_type m;
m.insert(std::make_pair("int", any_option(5)));
m.insert(std::make_pair("double", any_option(3.14)));
po::options_description desc;
BOOST_FOREACH(pair_type& pair, m)
{
pair.second.add_option(desc, pair.first.c_str());
}
// etc.
}
Let me know if something is unclear. :)
template<class T>
bool any_is(const boost::any& a)
{
try
{
boost::any_cast<const T&>(a);
return true;
}
catch(boost::bad_any_cast&)
{
return false;
}
}
// ...
po::options_description desc;
std::for_each(m_Config.getTuples().begin(),
m_Config.getTuples().end(),
[&desc](const TuplePair& _pair)
{
if(any_is<int>(_pair.first))
{
desc.add_options() { _pair.first, po::value<int>, ""};
}
else if(any_is<std::string>(_pair.first))
{
desc.add_options() { _pair.first, po::value<std::string>, ""};
}
else
{
// ...
}
});
// ...
If you have more than a handful of types consider using typelists.