Creating enum from variadic arguments? - c++

In some other langauges you can specify enums along with states, eg.:
public enum Planet {
MERCURY (3.303e+23, 2.4397e6),
VENUS (4.869e+24, 6.0518e6),
EARTH (5.976e+24, 6.37814e6),
MARS (6.421e+23, 3.3972e6),
JUPITER (1.9e+27, 7.1492e7),
SATURN (5.688e+26, 6.0268e7),
URANUS (8.686e+25, 2.5559e7),
NEPTUNE (1.024e+26, 2.4746e7);
...
This isn't hard to emulate in c++ - but only it easily becomes somewhat verbose.
I know this has been asked before and similar questions exists, e.g. in Build an enum using variadic template parameters, but I wanted to ask this again and have slightly different perspective.
Consider the following 'hand-written' approach:
#pragma warning(error : 4062)
enum tvtype {
black_and_white,
color
};
struct TvType {
tvtype tvtype_;
constexpr TvType(tvtype type) : tvtype_{type} {
}
constexpr operator tvtype() const {
return tvtype_;
}
};
constexpr TvType BlackAndWhite(black_and_white);
constexpr TvType Color(color);
bool hasColor(TvType tv) {
switch (tv) {
case BlackAndWhite:
return false;
//case Color:
//return true;
};
return false;
}
Try it yourself (comment in the two lines in the switch to make it compile)
This method is working well - only it is somewhat verbose.
Using this method it should now be possible to store some extra information along with the enum value, like a string representation, perhaps adding functions as well, etc.
Also because it's actually an enum underneath, it's possible for the compiler to check that all cases have been checked in the switch (the example above should generates a compile error due that the 'color' case is outcommented).
I'm interested in a generic / templated way of getting the enum generated or something similar that fulfills the requirement of compiler checked switch and extensibility.
But in order to templatize the above, it seems the enum should be generated in a (compile-time) programatical way, which leads to the question:
Is it possible to create an enum from a fold expression for instance or failing that from some kind of recursive template ?

Is it possible to create an enum from a fold expression for instance or failing that from some kind of recursive template ?
Not with variadic templates. Template arguments can be types, or constant values. You can't substitute a symbol to stick it inside an enum block.
However, you can do that with macros. Only trouble is, while C++11 has something called "variadic macros", it's very limited.
#define MY_MACRO(...) enum { __VA_ARGS__ }
You can't do any kind of transformation on variadic arguments like you can with templates, it literally just replaces __VA_ARGS___ with all the tokens the ... represents.
But, using the technique from this great answer: https://stackoverflow.com/a/11763277/1863938 , you can support "up to N" variadic solutions. Using that, you can create a macro that templates your boilerplate class for up to N values. Below is for up to 4 symbols:
#define _JENUM_GET_MACRO(_1,_2,_3,_4,NAME,...) NAME
#define _JENUM_VALUE_DEF1(_1) _##_1##_v_
#define _JENUM_VALUE_DEF2(_1,_2) _JENUM_VALUE_DEF1(_1), _JENUM_VALUE_DEF1(_2)
#define _JENUM_VALUE_DEF3(_1,_2,_3) _JENUM_VALUE_DEF1(_1), _JENUM_VALUE_DEF1(_2), _JENUM_VALUE_DEF1(3)
#define _JENUM_VALUE_DEF4(_1,_2,_3,_4) _JENUM_VALUE_DEF1(_1), _JENUM_VALUE_DEF1(_2), _JENUM_VALUE_DEF1(3), _JENUM_VALUE_DEF1(_4)
#define _JENUM_VALUE_DEF(...) _JENUM_GET_MACRO(__VA_ARGS__, _JENUM_VALUE_DEF4, _JENUM_VALUE_DEF3, _JENUM_VALUE_DEF2, _JENUM_VALUE_DEF1)(__VA_ARGS__)
#define _JENUM_ENUM_DEF(name, ...) enum _##name##_e_ { _JENUM_VALUE_DEF(__VA_ARGS__) };
#define _JENUM_CLASS_DEF(name) struct name {\
_##name##_e_ _value;\
constexpr name(const name& that) : _value(that._value) { }\
constexpr name(_##name##_e_ _value) : _value(_value) { }\
constexpr operator _##name##_e_() const { return _value; }\
};\
#define _JENUM_CONST_DEF1(name, _1) constexpr name _1(_JENUM_VALUE_DEF1(_1));
#define _JENUM_CONST_DEF2(name, _1,_2) _JENUM_CONST_DEF1(name, _1) _JENUM_CONST_DEF1(name, _2)
#define _JENUM_CONST_DEF3(name, _1,_2,_3) _JENUM_CONST_DEF1(name, _1) _JENUM_CONST_DEF1(name, _2) _JENUM_CONST_DEF1(name, _3)
#define _JENUM_CONST_DEF4(name, _1,_2,_3,_4) _JENUM_CONST_DEF1(name, _1) _JENUM_CONST_DEF1(name, _2) _JENUM_CONST_DEF1(name, _3) _JENUM_CONST_DEF1(name, _4)
#define _JENUM_CONST_DEF(name, ...) _JENUM_GET_MACRO(__VA_ARGS__, _JENUM_CONST_DEF4, _JENUM_CONST_DEF3, _JENUM_CONST_DEF2, _JENUM_CONST_DEF1)(name, __VA_ARGS__)
#define JENUM(name, ...)\
_JENUM_ENUM_DEF(name, __VA_ARGS__)\
_JENUM_CLASS_DEF(name)\
_JENUM_CONST_DEF(name, __VA_ARGS__)
... just follow the pattern to add more overloads
Then, to use:
JENUM(TvType, BlackAndWhite, Color);
Now, if you want to add methods and whatnot, it's easier to just inherit than to try and work anything into the macro:
struct TvTypeEx : public TvType {
using TvType::TvType;
TvTypeEx(TvType that) : TvType(that) { }
bool hasColor() const { return *this == Color; }
};
Now you can do stuff like:
TvTypeEx tv = Color;
return tv.hasColor() ? GetColorContent() : GetBlackAndWhiteContent();
Demo: https://godbolt.org/z/rdqS65

Related

Deduce the type of a declaration

I am writing a macro that takes a declaration as its single argument. Is it possible to deduce the type of the declaration inside the macro without splitting up the single argument into separate type and identifier arguments?
#define M(declaration) \
declaration; \
static_assert(sizeof(/* deduce type of 'declaration' */) == 4, "!")
M(int i);
M(double d{3.14});
M(std::string s{"Hello, world!"});
The following implementation would work but it feels less user-friendly (imo):
#define M(type, identifier) \
type identifier; \
static_assert(sizeof(type) == 4, "!")
M(int, i);
M(double, d{3.14});
M(std::string, s{"Hello, world!"});
If possible, I would prefer to take the declaration as a single argument.
Related question: Macro to get the type of an expression; but I failed to get that code to work in my example (compiler error: expected nested-name-specifier).
If your static assertion message is really that simple "!"1, I suggest you ditch the preprocessor. Make the type system work for you instead:
namespace detail {
template<typename T>
struct check_declared_type {
using type = T;
static_assert(sizeof(type) == 4, "!");
};
}
template<typename T>
using M = typename detail::check_declared_type<T>::type;
// .. Later
int main() {
M<int> i;
M<double> d{3.14};
M<std::string> s{"Hello, world!"};
}
1 - Specifically, if you don't need the preprocessor to stringify anything for you.
This macro ought to work for all your examples, but it does have a nasty issue:
#define M(declaration) \
declaration; \
do { \
struct dummy__ { declaration; }; \
static_assert(sizeof(dummy__) == 4, "!"); \
} while (false)
The problem is that an initializer within a class definition must use either the = token or a braced-init-list at top level, and not parentheses at top level. So for example M(SomeClass obj(true, 3)); won't compile, even if sizeof(SomeClass)==4. Since braced initializers are not entirely equivalent to parenthesis initializers, this means some declarations would be impossible to use with the macro.

Error contains no argument packs when redefine a macro [duplicate]

Say I have a macro like this:
#define SET_TYPE_NAME(TYPE, NAME) \
template<typename T> \
std::string name(); \
\
template<> \
std::string name<TYPE>() { \
return NAME; \
}
This won't work if I pass it a template that has more than one parameter, because the comma in the <int, int> is interpreted as separating the macro arguments, not the template arguments.
SET_TYPE_NAME(std::map<int, int>, "TheMap")
// Error: macro expects two arguments, three given
This problem seems to be solved by doing this:
SET_TYPE_NAME((std::map<int, int>), "TheMap")
But now another problem arises, one that I really did not expect:
template<>
std::string name<(std::map<int, int>)>()
// template argument 1 is invalid
It seems that the extra parentheses make the template argument invalid. Is there any way around this?
Besides typedef, you could switch the order of the arguments and use variadic macros (requires C99 or C++11-compatible compiler):
#define SET_TYPE_NAME(NAME, ...) \
template<typename T> \
std::string name(); \
\
template<> \
std::string name<__VA_ARGS__>() { \
return NAME; \
}
...
SET_TYPE_NAME("TheMap", std::map<int, int>)
You could use typedef:
typedef std::map<int, int> int_map;
SET_TYPE_NAME(int_map, "TheMap");
boost's BOOST_FOREACH suffers from the same issue.
Some time ago (while searching the web for the utility of Identity<T>) I got to this page.
In brief, to answer the question, if you don't have C++11 support and/or can't (or don't want to) use a typedef, you call your macro the "right" way:
// If an argument contains commas, enclose it in parentheses:
SET_TYPE_NAME((std::map<int, int>), "TheMap")
// For an argument that doesn't contain commas, both should work:
SET_TYPE_NAME((SomeType1), "TheType1")
SET_TYPE_NAME(SomeType2, "TheType2")
and then to get rid of the (possible) unwanted parentheses around the type, you can use a "helper" like this:
template<typename> struct RemoveBrackets;
template<typename T> struct RemoveBrackets<void (T)> {
typedef T Type;
};
and in your macro change the line:
std::string name<TYPE>() { \
to:
std::string name< RemoveBrackets<void (TYPE)>::Type >() { \
(or define a helper macro, say
#define REMOVE_BRACKETS(x) RemoveBrackets<void (x)>::Type
then replace the line with
std::string name< REMOVE_BRACKETS(TYPE) >() { \
).
(For the full story read the paragraph "An even better solution" at the end of the article linked above.)
Edit: just found that. But it uses <void X> when it really should use <void (X)> (in get_first_param<void X>::type); indeed the parentheses are necessary if you pass a "simple", non-bracketed argument (like SomeType2 in my code above) -- and they don't hurt if X is already bracketed (e.g., void ((SomeType1)) is equivalent to void (SomeType1); again, see the article). (By the way, I noticed that many answers on the other SO page are in essence "Macros are dumb". I won't comment, though.)
I'd like to add an answer to my own question. Now that Boost 1.50.0 was released, Boost.Utility has a new mini-library that helps with this kind of thing. If you look at the source you'll see it's implemented the same as gx_'s solution. Here's how to use it:
#include <boost/utility/identity_type.hpp>
SET_TYPE_NAME(BOOST_IDENTITY_TYPE((std::map<int, int>)), "TheMap");
http://www.boost.org/doc/libs/1_50_0/libs/utility/identity_type/doc/html/index.html
I like the typedef way proposed by hmjd better, but for the record, the usual way I've seen around this is to kick the angle brackets out of the macro and write:
#define SET_TYPE_NAME(TYPE, NAME) \
template<typename T> \
std::string name(); \
\
template<> \
std::string name TYPE() { \
return NAME; \
}
Usage:
SET_TYPE_NAME(<std::map<int, int> >, "TheMap")
This is a variation of an old technique used for error message reporting and fprintf:
#define Error(args) do { \
printf("ERROR: "); \
printf args; \
printf("\n"); \
return 1; \
} while(0)
Called with:
Error(("Index out of range: %d not in %d ... %d.", var, min, max));
It's ugly but it worked. Useful if the coding style rules ban typedef.
typedef std::map<int,int> IntMap_t;
SET_TYPE_NAME(IntMap_t, "TheMap")
You can declare a typedef and use it in the macro
A more generic way is to always use () around your arguments that may contain a comma and use CONCAT to remove the parenthesis. If you do so, you can define multiple parameters packs wits comma inside or put arguments in your favorite order
#ifndef CONCAT
#define CONCAT __VA_ARGS__
#endif
#define MYMACRO(tparam,classname)\
template < CONCAT tparam >\
class CONCAT classname {};
//create a template class X<T,U>
MYMACRO( (typename T,typename U) , (X<T,U>) )
I know this is an old question. Though this comes in top results on a Google search and nobody has yet mentioned an even more simple solution by defining a macro for the comma:
#define COMMA ,
SET_TYPE_NAME(std::map<int COMMA int>, "TheMap")

The same name macro with different arguments

Is it possible to have 2 macros with the same name, but different arguments? Something like this:
#define FI(value) do {l<<value; Doit(l); } while(0)
#define FI(value, level) do {l<<value ; Doit(l,level); } while(0)
It is not possible.
A symbol name cannot be redefined. Unlike functions macros cannot be overloaded. Think of it logically macros are for pure textual replacement, So how can you replace two different things for the same entity?
An alternative and better solution:
You can write a inline function for achieving the same result. It provides you additional advantage of type checking and saves you from the murky side effects of macros.
This would work.
#define FI(value, ...) FI_(value, ##__VA_ARGS__, 2, 1)
#define FI_(value, level, n, ...) FI##n(value, level)
#define FI1(value, ...) do {l << value; Doit(l);} while (0)
#define FI2(value, level) do {l << value; Doit(l, level);} while (0)
Actually it is possible. However, it will result in compiler warning regarding redefinition.
See this for more details:
http://efesx.com/2010/08/31/overloading-macros/
This is a situation in which you really should use inline functions. Knowing nothing about the types you are using, a possible implementation might look like this:
template<typename T>
inline void fi(T & l, const T & value) {
l << value;
Doit(l);
}
template<typename T>
inline void fi(T & l, const T & value, const T & level) {
l << value;
Doit(l, level);
}
If you ever encounter a situation in which you have to stick to macros, you will have to work-around this limitation that they can't be overloaded, at least not per the standard. To "overload" them, we just write the number of arguments on the name of the macro, which is a common way to do so (in fact, even the OpenGL library uses this method to "overload" C functions).
#define FI1(value) do {l<<value; Doit(l); } while(0)
#define FI2(value, level) do {l<<value ; Doit(l,level); } while(0)

How to pass multi-argument templates to macros?

Say I have a macro like this:
#define SET_TYPE_NAME(TYPE, NAME) \
template<typename T> \
std::string name(); \
\
template<> \
std::string name<TYPE>() { \
return NAME; \
}
This won't work if I pass it a template that has more than one parameter, because the comma in the <int, int> is interpreted as separating the macro arguments, not the template arguments.
SET_TYPE_NAME(std::map<int, int>, "TheMap")
// Error: macro expects two arguments, three given
This problem seems to be solved by doing this:
SET_TYPE_NAME((std::map<int, int>), "TheMap")
But now another problem arises, one that I really did not expect:
template<>
std::string name<(std::map<int, int>)>()
// template argument 1 is invalid
It seems that the extra parentheses make the template argument invalid. Is there any way around this?
Besides typedef, you could switch the order of the arguments and use variadic macros (requires C99 or C++11-compatible compiler):
#define SET_TYPE_NAME(NAME, ...) \
template<typename T> \
std::string name(); \
\
template<> \
std::string name<__VA_ARGS__>() { \
return NAME; \
}
...
SET_TYPE_NAME("TheMap", std::map<int, int>)
You could use typedef:
typedef std::map<int, int> int_map;
SET_TYPE_NAME(int_map, "TheMap");
boost's BOOST_FOREACH suffers from the same issue.
Some time ago (while searching the web for the utility of Identity<T>) I got to this page.
In brief, to answer the question, if you don't have C++11 support and/or can't (or don't want to) use a typedef, you call your macro the "right" way:
// If an argument contains commas, enclose it in parentheses:
SET_TYPE_NAME((std::map<int, int>), "TheMap")
// For an argument that doesn't contain commas, both should work:
SET_TYPE_NAME((SomeType1), "TheType1")
SET_TYPE_NAME(SomeType2, "TheType2")
and then to get rid of the (possible) unwanted parentheses around the type, you can use a "helper" like this:
template<typename> struct RemoveBrackets;
template<typename T> struct RemoveBrackets<void (T)> {
typedef T Type;
};
and in your macro change the line:
std::string name<TYPE>() { \
to:
std::string name< RemoveBrackets<void (TYPE)>::Type >() { \
(or define a helper macro, say
#define REMOVE_BRACKETS(x) RemoveBrackets<void (x)>::Type
then replace the line with
std::string name< REMOVE_BRACKETS(TYPE) >() { \
).
(For the full story read the paragraph "An even better solution" at the end of the article linked above.)
Edit: just found that. But it uses <void X> when it really should use <void (X)> (in get_first_param<void X>::type); indeed the parentheses are necessary if you pass a "simple", non-bracketed argument (like SomeType2 in my code above) -- and they don't hurt if X is already bracketed (e.g., void ((SomeType1)) is equivalent to void (SomeType1); again, see the article). (By the way, I noticed that many answers on the other SO page are in essence "Macros are dumb". I won't comment, though.)
I'd like to add an answer to my own question. Now that Boost 1.50.0 was released, Boost.Utility has a new mini-library that helps with this kind of thing. If you look at the source you'll see it's implemented the same as gx_'s solution. Here's how to use it:
#include <boost/utility/identity_type.hpp>
SET_TYPE_NAME(BOOST_IDENTITY_TYPE((std::map<int, int>)), "TheMap");
http://www.boost.org/doc/libs/1_50_0/libs/utility/identity_type/doc/html/index.html
I like the typedef way proposed by hmjd better, but for the record, the usual way I've seen around this is to kick the angle brackets out of the macro and write:
#define SET_TYPE_NAME(TYPE, NAME) \
template<typename T> \
std::string name(); \
\
template<> \
std::string name TYPE() { \
return NAME; \
}
Usage:
SET_TYPE_NAME(<std::map<int, int> >, "TheMap")
This is a variation of an old technique used for error message reporting and fprintf:
#define Error(args) do { \
printf("ERROR: "); \
printf args; \
printf("\n"); \
return 1; \
} while(0)
Called with:
Error(("Index out of range: %d not in %d ... %d.", var, min, max));
It's ugly but it worked. Useful if the coding style rules ban typedef.
typedef std::map<int,int> IntMap_t;
SET_TYPE_NAME(IntMap_t, "TheMap")
You can declare a typedef and use it in the macro
A more generic way is to always use () around your arguments that may contain a comma and use CONCAT to remove the parenthesis. If you do so, you can define multiple parameters packs wits comma inside or put arguments in your favorite order
#ifndef CONCAT
#define CONCAT __VA_ARGS__
#endif
#define MYMACRO(tparam,classname)\
template < CONCAT tparam >\
class CONCAT classname {};
//create a template class X<T,U>
MYMACRO( (typename T,typename U) , (X<T,U>) )
I know this is an old question. Though this comes in top results on a Google search and nobody has yet mentioned an even more simple solution by defining a macro for the comma:
#define COMMA ,
SET_TYPE_NAME(std::map<int COMMA int>, "TheMap")

How can one make a 'passthru' function in C++ using macros or metaprogramming?

So I have a series of global functions, say:
foo_f1(int a, int b, char *c);
foo_f2(int a);
foo_f3(char *a);
I want to make a C++ wrapper around these, something like:
MyFoo::f1(int a, int b, char* c);
MyFoo::f2(int a);
MyFoo::f3(char* a);
There's about 40 functions like this, 35 of them I just want to pass through to the global function, the other 5 I want to do something different with.
Ideally the implementation of MyFoo.cpp would be something like:
PASSTHRU( f1, (int a, int b, char *c) );
PASSTHRU( f2, (int a) );
MyFoo::f3(char *a)
{
//do my own thing here
}
But I'm having trouble figuring out an elegant way to make the above PASSTHRU macro.
What I really need is something like the mythical X getArgs() below:
MyFoo::f1(int a, int b, char *c)
{
X args = getArgs();
args++; //skip past implicit this..
::f1(args); //pass args to global function
}
But short of dropping into assembly I can't find a good implementation of getArgs().
You could use Boost.Preprocessor to let the following:
struct X {
PASSTHRU(foo, void, (int)(char))
};
... expand to:
struct X {
void foo ( int arg0 , char arg1 ) { return ::foo ( arg0 , arg1 ); }
};
... using these macros:
#define DO_MAKE_ARGS(r, data, i, type) \
BOOST_PP_COMMA_IF(i) type arg##i
#define PASSTHRU(name, ret, args) \
ret name ( \
BOOST_PP_SEQ_FOR_EACH_I(DO_MAKE_ARGS, _, args) \
) { \
return ::name ( \
BOOST_PP_ENUM_PARAMS(BOOST_PP_SEQ_SIZE(args), arg) \
); \
}
At 40-odd functions, you could type the wrappers out by hand in an hour. The compiler will check the correctness of the result. Assume an extra 2 minutes for each new function that needs wrapping, and an extra 1 minute for a change in signature.
As specified, and with no mention of frequent updates or changes, it doesn't sound like this problem requires a cunning solution.
So, my recommendation is to keep it simple: do it by hand. Copy prototypes into source file, then use keyboard macros (emacs/Visual Studio/vim) to fix things up, and/or multiple passes of search and replace, generating one set of definitions and one set of declarations. Cut declarations, paste into header. Fill in definitions for the non-passing-through functions. This won't win you any awards, but it'll be over soon enough.
No extra dependencies, no new build tools, works well with code browsing/tags/intellisense/etc., works well with any debugger, and no specialized syntax/modern features/templates/etc., so anybody can understand the result. (It's true that nobody will be impressed -- but it will be the good kind of unimpressed.)
Slightly different syntax but...
#include <boost/preprocessor.hpp>
#include <iostream>
void f1(int x, int y, char* z) { std::cout << "::f1(int,int,char*)\n"; }
#define GENERATE_ARG(z,n,unused) BOOST_PP_CAT(arg,n)
#define GET_ARGS(n) BOOST_PP_ENUM(n, GENERATE_ARG, ~)
#define GENERATE_PARAM(z,n,seq) BOOST_PP_SEQ_ELEM(n,seq) GENERATE_ARG(z,n,~)
#define GENERATE_PARAMS(seq) BOOST_PP_ENUM( BOOST_PP_SEQ_SIZE(seq), GENERATE_PARAM, seq )
#define PASSTHROUGH(Classname, Function, ArgTypeSeq) \
void Classname::Function( GENERATE_PARAMS(ArgTypeSeq) ) \
{ \
::Function( GET_ARGS( BOOST_PP_SEQ_SIZE(ArgTypeSeq) ) ); \
}
struct test
{
void f1(int,int,char*);
};
PASSTHROUGH(test,f1,(int)(int)(char*))
int main()
{
test().f1(5,5,0);
std::cin.get();
}
You could get something closer to yours if you use tuples, but you'd have to supply the arg count to the base function (you can't derive a size from a tuple). Sort of like so:
PASSTHROUGH(test,f1,3,(int,int,char*))
That about what you're looking for? I knew it could be done; took about a half hour to solve. You seem to expect that there's an implicit 'this' that has to be gotten rid of but I don't see why...so maybe I misunderstand the problem. At any rate, this will let you quickly make default "passthrough" member functions that defer to some global function. You'll need a DECPASSTHROUGH for the class declaration if you want to skip having to declare them all...or you could modify this to make inline functions.
Hint: Use BOOST_PP_STRINGIZE((XX)) to test the output of preprocessor metafunctions.
My initial thought, and this probably won't work or others would have stated this, is to put all your base functions together in a class as virtual. Then, write the functionality improvements into inherited classes and run with it. It's not a macro wrapper, but you could always call the global functions in the virtual classes.
With some assembly trickery, you could probably do exactly what you'd want, but you would lose portability more than likely. Interesting question and I want to hear other's answers as well.
You may want to use a namespace if you want to not deal with class stuff, like this. You could also use static member methods in a class, but I think that people don't like that anymore.
#ifndef __cplusplus
#define PASSTHRU(type, prefix, func, args) type prefix##_##func args
#else
#define PASSTHRU(type, prefix, func, args) type prefix::func args
#endif
Or
#ifndef __cplusplus
#define PASSTHRU(type, prefix, func, ...) type prefix##_##func(__VA_ARGS__)
...
Perfect forwarding relies on rvalue references. STL has a blog entry on it at Link and you would want to choose a compiler that supported the feature to take this approach. He's discussing Visual C++ 2010.