Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Macro to get the type of an expression

Question

I am trying to write a C++ macro that would take either type or type name as input, and give type as output.

For example:
REMOVE_NAME(int) should be int
REMOVE_NAME(int aNumber) should also be int

I managed to write such a macro (below) and it works, but I'm wondering whether I'm missing a simpler way to accomplish this.

#include <boost/type_traits.hpp>

template <typename T>
struct RemoveNameVoidHelper
{
    typedef typename T::arg1_type type;
};

template <>
struct RemoveNameVoidHelper<boost::function_traits<void()>>
{
    typedef void type;
};

#define REMOVE_NAME(expr) RemoveNameVoidHelper<boost::function_traits<void(expr)>>::type

Any ideas?

Motivation

I'm using this macro to aid with code generation. I have another macro which is used to declare certain methods in class definitions:

#define SLOT(name, type)                            \
    void Slot##name(REMOVE_NAME(type) argument)     \
    {                                               \
        /* Something that uses the argument. */     \
    }                                               \
    void name(type)

I want the user of the SLOT macro to be able to comfortably choose whether he wants to implement his slots inside or outside the class, just like with normal methods. This means that SLOT's type argument can be either a type, or a type with a name. For example:

class SomeClass
{
    SLOT(ImplementedElsewhere, int);
    SLOT(ImplementedHere, int aNumber)
    {
        /* Something that uses aNumber. */
    }
};

Without the REMOVE_NAME macro, my automatically generated Slot... method will not be able to specify its own name for its argument, and thus it will not be able to refer to it.

Of course, this is not the only possible use for this macro.

like image 767
Corvus Corax Avatar asked Sep 03 '12 13:09

Corvus Corax


1 Answers

I think you're correct; as far as I can tell the only other production where a decl-specifier-seq or type-specifier-seq is followed by an optional declarator is a catch statement, and I don't think that's much use for type extraction. The production parameter-declaration is also used in template-parameter-list, but that's not much use either.

I might define your macro like this, removing the dependency on Boost:

template<typename T> struct remove_name_helper {};
template<typename T> struct remove_name_helper<void(T)> { typedef T type; };
template<> struct remove_name_helper<void()> { typedef void type; };

#define REMOVE_NAME(expr) typename remove_name_helper<void(expr)>>::type
like image 175
ecatmur Avatar answered Nov 06 '22 02:11

ecatmur