Related
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.
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")
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 do you write a macro with variable number of arguments to define a function? Suppose that we define the class class1 with 2 parameters and class class2 with three parameters.
class class1 {
public:
int arg1;
int arg2;
class1(int x1, int x2): arg1(x1), arg2(x2) {}
};
class class2 {
public:
int arg1;
int arg2;
int arg3;
class1(int x1, int x2, int x3): arg1(x1), arg2(x2), arg3(x3) {}
};
For each class that I define or even classes that have been defined before I want to write the following:
template<> inline void writeInfo<class1>(const class1& obj, FILE* fp) {
writeAmount(2, fp);
writeName("arg1", fp);
writeInfo(obj.arg1, fp);
writeName("arg2", fp);
writeInfo(obj.arg2, fp);
}
template<> inline void writeInfo<class2>(const class2& obj, FILE* fp) {
writeAmount(3, fp);
writeName("arg1", fp);
writeInfo(obj.arg1, fp);
writeName("arg2", fp);
writeInfo(obj.arg2, fp);
writeName("arg3", fp);
writeInfo(obj.arg3, fp);
}
We do not need to care about the definitions of writeAmount, writeName or writeInfo. What I would like to do is write something like:
MACROWRITEINFO(class1, 2, arg1, arg2);
MACROWRITEINFO(class2, 3, arg1, arg2, arg3);
Is it possible to create such macro so that it can expand to the above template definitions? I've read in a lot of places that macros are evil, but in this case I believe that they are very helpful since they'll reduce the amount of code I type and thus the amount of typos I'll make during the creation of the template functions.
First of all you should improve your formatting/code. Your code lacks "class" keywords and semicolons after classes definitions - when you post a snippet make sure it's proper code, because some people (i.e. me) will try to compile it.
Second of all, dont use function template specialization. If macros are evil, then they must be satan incarnation. Just stick to the good old overloads. See here for details.
And at least - an answer. You could mess around with variadic macros if all args were of the same type - for example, you could create an array inside writeInfo function and iterate over elements. Since it's cleary not the case here you can define many variants of MACROWRITEINFO macro for different number of parameteres, using some common blocks to reduce code repetition. For example:
#define MACROWRITEINFO_BEGIN(type, amount) \
void writeInfo(const type& obj, FILE* fp) \
{ \
writeAmount(amount, fp);
#define MACROWRITEINFO_NAMEINFO(name) \
writeName(#name, fp); \
writeInfo(obj.##name, fp);
#define MACROWRITEINFO_END() \
}
Using those you can now define variants based on number of arguments.
#define MACROWRITEINFO1(type, arg1) \
MACROWRITEINFO_BEGIN(type, 1) \
MACROWRITEINFO_NAMEINFO(arg1) \
MACROWRITEINFO_END()
#define MACROWRITEINFO2(type, arg1, arg2) \
MACROWRITEINFO_BEGIN(type, 2) \
MACROWRITEINFO_NAMEINFO(arg1) \
MACROWRITEINFO_NAMEINFO(arg2) \
MACROWRITEINFO_END()
And so on...
EDIT:
Well I guess it is possible to use variadic macros here. Take at look at this SO question. It's pure madness, but you should be able to achieve what you want.
EDIT:
My idea was to expand variadic arguments into array then iterate over them; if they were of the same type, let's say int, you could write:
#define VAARGSSAMPLE(...) \
int args[] = { __VA_ARGS__ }; \
for (int i = 0; i < sizeof(args)/sizeof(int); ++i) \
{ \
printf("%d\n", args[i]); \
}
VAARGSSAMPLE(1, 5, 666);
So if all your variables were of the same type you could put them in an array. But they are not, so it won't do. If you really, really want to stick to variadic arguments go to my first edit.
I don't think it's possible to do that with a macro. You can use variable arguments (variadic) but you can't generate code which depends on the arguments.
I'd suggest you create a DSL (e.g. simple xml..) and generate code out of it. this is much cleaner and good practice.
You could do this:
<writeInfos>
<writeInfo class="class1" amount="3">
<arguments>
<argument>arg1</argument>
<argument>arg2</argument>
</arguments>
</writeInfo>
</writeInfos>
Then create source code out of this. You should add this step in your build process..
But you can also define something much simpler.. you could put your MACROWRITEINFO "functions" in a text file and parse it yourself..
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.