TL;DR
What are the available tricks to pass undefined number of template classes to a macro in C++17 ? Example: my_macro(std::map<std::string,std::vector<double>>, double, std::deque<std::pair<bool,double>>)
With context
I'm in a context where I declare wrapper classes through macros. In these classes, I have a static function (written by a macro) to expose the wrapper in the API. Something like that:
wrapper_declare(Foo) // <- This is a macro declaring the template class, the
public: // inheritence, and some constructors
void foo(double x);
int bar() const;
wrapper_expose(Foo, foo, bar); // <- This macro using __VA_ARGS__ defines a function 'expose'
};
It will be replaced by something like that:
template <>
class Wrapper<Foo> : public WrapperBase<Foo>
{
private:
typedef Wrapper<Foo> this_class;
typedef WrapperBase<Foo> super;
public:
Wrapper() : WrapperBase<Foo>() { this->initEmpty(); }
Wrapper(Wrapper<Foo> const&) = default;
~Wrapper() noexcept = default;
public:
void foo(double x);
int bar() const;
void expose()
{
magical_exposer<Foo>()
.add("foo", &Wrapper<Foo>::foo)
.add("bar", &Wrapper<Foo>::bar);
// Yes, actually it's boost::python ;-)
}
};
Note: I also have a generic wrapper for template types, where I can define classes like Wrapper<Hello<int,float,std::string>>
. It will be a part of my problem below.
The expose
function has also to expose dependencies on several other wrapped classes. Example:
template <>
class Wrapper<Foo> : public WrapperBase<Foo>
{
private:
typedef Wrapper<Foo> this_class;
typedef WrapperBase<Foo> super;
public:
Wrapper() : WrapperBase<Foo>() { this->initEmpty(); }
Wrapper(Wrapper<Foo> const&) = default;
~Wrapper() noexcept = default;
public:
void foo(double x);
Wrapper<Bar> bar() const; // <- now return another wrapper
void expose()
{
Wrapper<Bar>::expose(); // <- have to expose it before
magical_exposer<Foo>()
.add("foo", &Wrapper<Foo>::foo)
.add("bar", &Wrapper<Foo>::bar);
// Yes, actually it's boost::python ;-)
}
};
With this approach, if I want to define this function with a macro, I have to pass the exposed types. Two problems with that:
- the number of dependencies is not fixed, and
__VA_ARGS__
is already used by the macro for the functions to expose - the exposed wrapper can contains comma, a problem with macros.
I imaginated a trick using a tuple type declared in the class and used by the expose
function. Something like:
template <>
class Wrapper<Foo> : public WrapperBase<Foo>
{
private:
typedef Wrapper<Foo> this_class;
typedef WrapperBase<Foo> super;
public:
Wrapper() : WrapperBase<Foo>() { this->initEmpty(); }
Wrapper(Wrapper<Foo> const&) = default;
~Wrapper() noexcept = default;
public:
void foo(double x);
Wrapper<Bar> bar() const;
Wrapper<Hello<int,float,std::string>> hello() const;
typedef std::tuple<Wrapper<Bar>,Wrapper<Hello<int,float,std::string>>> dependencies__;
void expose()
{
dependencies__ d__;
std::apply([](auto x){ decltype(x)::expose(); }, d__);
magical_exposer<Foo>()
.add("foo", &Wrapper<Foo>::foo)
.add("bar", &Wrapper<Foo>::bar);
// Yes, actually it's boost::python ;-)
}
};
The typedef can be declared by the following macros
#define wrapper_dependencies(...) typedef std::tuple<__VA_ARGS__> dependencies__;
#define wrapper_no_dependencies() typedef std::tuple<> dependencies__;
But... I'm a little bit maniac. Most of my wrapped classes have no dependencies. Then I would like to have the call to wrapper_no_dependencies()
as default, without having to write it. But it seems there is no way to overwrite a typedef
.
Have you some ideas how to do that (maybe with another trick than the tuple) ?