Макрос для получения типа выражения

Вопрос

Я пытаюсь написать макрос C++, который будет принимать либо type, либо type name в качестве входных данных и давать type в качестве выходных данных.

Например:
REMOVE_NAME(int) должно быть int
REMOVE_NAME(int aNumber) также должно быть int

Мне удалось написать такой макрос (ниже), и он работает, но мне интересно, не упустил ли я более простой способ сделать это.

#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

Любые идеи?

Мотивация

Я использую этот макрос, чтобы помочь с генерацией кода. У меня есть еще один макрос, который используется для объявления определенных методов в определениях классов:

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

Я хочу, чтобы пользователь макроса SLOT мог удобно выбирать, хочет ли он реализовать свои слоты внутри или вне класса, как и в случае с обычными методами. Это означает, что аргумент типа SLOT может быть либо типом, либо типом с именем. Например:

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

Без макроса REMOVE_NAME мой автоматически сгенерированный метод Slot... не сможет указать собственное имя для своего аргумента и, следовательно, не сможет ссылаться на него.

Конечно, это не единственное возможное использование этого макроса.


person Corvus Corax    schedule 03.09.2012    source источник
comment
Ага. Проще было бы: не использовать для этого МАКРОС. Или если да, то просто указать имя отдельно?!   -  person sehe    schedule 03.09.2012
comment
Ознакомьтесь с decltype.   -  person Some programmer dude    schedule 03.09.2012
comment
Почему? Не могли бы вы использовать decltype С++ 11?   -  person Tom Tanner    schedule 03.09.2012
comment
decltype(int aNumber) является незаконным, к сожалению.   -  person Corvus Corax    schedule 03.09.2012
comment
Если вы хотите что-то более простое, было бы полезно, если бы вы могли объяснить, для чего вам это нужно и как вы планируете его использовать.   -  person Some programmer dude    schedule 03.09.2012
comment
Добавил мотивацию вопроса.   -  person Corvus Corax    schedule 03.09.2012
comment
(Относится к удаленному комментарию) Я не запрограммирую имя аргумента жестко. Реализация ImplementedHere идет под строкой void ImplementedHere(int aNumber). Жестко заданное имя argument используется только в сгенерированной макросом функции void SlotImplementedHere(int argument), о которой пользователь библиотеки ничего не знает. Я должен использовать там жестко заданное имя, иначе реализация AsyncImplementedHere (которая тоже генерируется тут же в макросе) не сможет ссылаться на собственный параметр.   -  person Corvus Corax    schedule 03.09.2012
comment
(Относится к удаленному комментарию) Макрос SLOT действительно является вариативным (здесь не показан), и когда пользователи реализуют свой слот, они указывают полные аргументы. Вот почему реализация ImplementedHere может относиться к aNumber.   -  person Corvus Corax    schedule 03.09.2012


Ответы (1)


Я думаю, вы правы; насколько я могу судить, это единственная другая продукция, в которой за decl-specifier-seq или type-specifier-seq следует необязательный декларатор является оператором catch, и я не думаю, что это очень полезно для извлечения типа. Производное объявление-параметров также используется в списке-параметров-шаблонов, но это тоже не очень полезно.

Я мог бы определить ваш макрос следующим образом, удалив зависимость от 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
person ecatmur    schedule 03.09.2012
comment
Спасибо! Это действительно лучше. Кстати, в вашей реализации специализация void не нужна — нужно было только обойти тот факт, что boost не определяет arg1_type, когда функция не имеет параметров. - person Corvus Corax; 03.09.2012