Проблема с параметрами шаблона, используемыми в макросах - PullRequest
21 голосов
/ 28 ноября 2010

Я пытаюсь скомпилировать следующий фрагмент кода, я получаю сообщение об ошибке в строке, которая специализируется на std :: vector, кажется, что один передаваемый параметр как-то считается двумя параметрами. Возможно, это связано с угловыми скобками?

Есть ли особый способ / механизм, по которому по таким параметрам можно корректно передать макросу

#include <vector>

template<typename A>
struct AClass {};

#define specialize_AClass(X)\
template<> struct AClass<X> { X a; };


specialize_AClass(int) //ok

specialize_AClass(std::vector<int,std::allocator<int> >) //error

int main()
{
   return 0;
}

Я получаю следующую ошибку:

1 Line 55: error: macro "specialize_AClass" passed 2 arguments, but takes just 1
2 Line 15: error: expected constructor, destructor, or type conversion before 'int'
3 compilation terminated due to -Wfatal-errors.

Ссылка: http://codepad.org/qIiKsw4l

Ответы [ 6 ]

10 голосов
/ 28 ноября 2010

У вас есть два варианта.Одно из которых уже упоминалось: использование __VA_ARGS__.Это, однако, имеет тот недостаток, что он не работает в строгом C ++ 03, но требует достаточно C99 / C ++ 0x-совместимого препроцессора.

Другой вариант - заключить в скобки имя типа.Но в отличие от утверждений о других ответах, это не так просто, как просто заключить в скобки имя типа.Пишем специализацию следующим образом - плохо сформировано

template<typename T> struct get_first_param;
template<typename R, typename P1> struct get_first_param<R(P1)> {
  typedef P1 type;
};

При этом get_first_param<void(X)>::type обозначает тип X.Теперь вы можете переписать свой макрос в

#define specialize_AClass(X) \
template<> struct AClass<get_first_param<void X>::type> { 
  get_first_param<void X>::type a; 
};

И вам просто нужно передать тип, заключенный в скобки.

9 голосов
/ 17 февраля 2011
template<typename TypeX, typename TypeY>
class Test
{
public:
    void fun(TypeX x, TypeY y)
    {
        std::wcout << _T("Hello") << std::endl;
        std::wcout << x << std::endl;
        std::wcout << y << std::endl;
    }
};

#define COMMOA ,

#define KK(x) x val;

void main()
{
    KK(Test<int COMMOA int>);
    val.fun(12, 13);
}

У меня есть новый способ решить эту проблему. надеюсь, что это может помочь вам:)

6 голосов
/ 28 ноября 2010

Здесь есть несколько проблем.

Прежде всего, макросы чрезвычайно глупы, они сложны, но по сути равносильны процессу замены чистого текста.

Поэтому есть2 (технические) проблемы с кодом, который вы раскрыли:

  1. Вы не можете использовать запятую в середине вызова макроса, она просто терпит неудачу, BOOST_FOREACH - это хорошо известная библиотека и пока единственнаяони могли сказать пользователю, что его аргументы не должны содержать запятых, если они не могут быть заключены в круглые скобки, что не всегда так
  2. Даже если замена произошла, ваш код потерпит неудачу в C ++03, потому что это создаст символ >> в конце специализации шаблона, который не будет анализироваться правильно.

Существуют приемы предварительной обработки / шаблонного метапрограммирования, однако более простое решение состоит в том, чтобыиспользуйте тип без запятых:

typedef std::vector<int, std::allocator<int> > FooVector;
specialize_AClass(FooVector)

Наконец, существует эстетическая проблема, поскольку из-за их распространенности макросы являютсяt имена, которые не могут конфликтовать с «обычными» (типами, функциями, переменными) именами.Консенсус обычно заключается в использовании всех идентификаторов в верхнем регистре, например:

SPECIALIZE_ACLASS

Обратите внимание, что это не может начинаться с подчеркивания, поскольку стандарт ограничивает использование идентификаторов, соответствующих _[A-Z].* или [^_]*__.*авторы компиляторов для стандартной библиотеки или что бы они ни чувствовали (это не смайлики: p)

2 голосов
/ 28 ноября 2010

Поскольку препроцессор запускается до семантического анализа, запятая в параметре шаблона интерпретируется как разделитель аргументов макроса.Вместо этого вы должны использовать переменные макросы, чтобы сделать что-то вроде этого:

#define specialize_AClass(...)\
template<> struct AClass< __VA_ARGS__ > { X a; };
1 голос
/ 02 февраля 2013

Если вы хотите добавить немного больше кода перед вызовом макроса, вы всегда можете сделать это в качестве обходного пути:

typedef std::vector<int,std::allocator<int> > myTypeDef; 
specialize_AClass(myTypeDef) //works
0 голосов
/ 28 ноября 2010

Есть много других проблем с вашим кодом, но для решения конкретного вопроса препроцессор просто обрабатывает < и > как операторы меньше и больше.

Это степеньего знания о C ++.

Есть несколько приемов, которые можно использовать для того, чтобы выражения шаблона могли передаваться в качестве аргументов макроса, но простой и чрезвычайно большой ответ best для ответановичок:

НЕ ДЕЛАЙТЕ ЭТОГО.

Приветствия и hth.,

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...