tags:

views:

218

answers:

5

Is there a way to pass

std::map<std::string, float>

as an argument to a macro?

(the problem is that the "," is used by the macro to split

std::map<std::string

and

float> 

as separate arguments. I would like to avoid this.

+1  A: 

One inelegant workaround is to "hide" the comma inside another macro

#define ARGUMENT std::map<std::string, float> 
YOUR_MACRO(ARGUMENT)
#undef ARGUMENT

However, if YOUR_MACRO itself needs to propagate it another level down into another macro, it will run into the same problem.

AndreyT
A `typedef` overcomes the nested-macro problem, but is rather more permanent.
Chris Lutz
I second the `typedef` approach. Whenever there is a substitute that does not involve a macro and provide the same ease of use... you're better off without a macro.
Matthieu M.
+4  A: 

No, there isn't a way to do this, short of using a typedef. BOOST_FOREACH, for example, suffers the same problem.

Martin B
+1 use a typedef
Autopulated
There are ways, if you're up to some preprocessing programming. It's may put some burden on the user though, depending on what you're after, and the macro needs to be tailored to handle it... see my answer.
Matthieu M.
+5  A: 

Try to use a template instead of the macro.

Scott Meyers : Effective C++ Item 2: Prefer consts, enums, and inlines to #defines

Totonga
The `Item 2` does not apply here: it does not mention templates, merely constants... and though I agree with the general sentiment, if it were always possible.. it would be great.
Matthieu M.
Its the inlines of Item 2. I mentioned templates here because macros do not care about types thats why you normally can not replace them by normal functions. But using templates can give you the ability to do so. I think Meyer used the min/max macro against template to demonstarte.
Totonga
A: 

I had something similar a few months back, if your using macro's and have parameters that contain comma's (','), you need to encase them in extra parenthasis ie:

#define DEF(ret,conv,name,args) typedef ret (conv * name)(args)

//usage
DEF(void,__cdecl,Foo,(int a1, string a2)); 

this method might conflict with certain things/be invalid in certain cases, like this example(it cause it to become an invalid c-style cast):

#define MY_VAR(type,name) type name

//usage
MY_VAR((std::map<std::string, float>),Map);

there is one way to address this problem though, but it requires your compiler to support variadic macros(GCC|MSVC):

#define _W(...) __VA_ARGS__
#define VAR(x,y) x y

VAR(_W(std::map<std::string, float>),Map);
Necrolis
Don't parenthesized `args` in the macro definition, it comes with parenthesis already.
Matthieu M.
if someone uses a singluar param, the parenthasis can be omitted when using the macro, which is why args is parenthasized, the rest of the time is does nothing, the superflous paranthasis are removed/ignored
Necrolis
The parenthesis don't seem to be ignored. The first example expands to `(std::map<std::string, float>) Map;` which simply doesn't compile (being a C-style cast on an undeclared identifier Map).
UncleBens
seems the first exmaple was a case where it didn't work out(the parenthasis are only ignored in the `DEF` macro), thanks for pointing it out, fixed it up with the 'correct' solution.
Necrolis
+3  A: 

Yes there is a way, it's indirect though.

As you have said, a macro is rather dumb in its interpretation. However it still recognize parenthesis.

Example: BOOST_MPL_ASSERT((boost::is_same<int,int>))

It works by using another level of parenthesis, thus forming a Tuple (from the macro point of view).

If you use the Boost.Preprocessor library, you can easily "unwrap" a Tuple to get its content unscathed. Unfortunately you are supposed to know the size of a tuple upfront, so you need an additional parameter

#define MY_MACRO(Size, TemplatedType, Name)\
  BOOST_PP_TUPLE_REM(Size)(TemplatedType) Name

And in action:

MY_MACRO(2, (std::map<int,std::string>), idToName);
    // expands to 'std::map<int,std::string> idToName'
idToName[1] = "Smith";

So, yes it is possible, but the macro has to be explicitly tailored to handle it.

Matthieu M.
I should add, also, that it may be cumbersome, since the user is required to count the number of `,` :/
Matthieu M.