Подтвердить что ты не робот

Проблема с параметрами шаблона, используемыми в макросах

Я пытаюсь скомпилировать следующий фрагмент кода, я получаю сообщение об ошибке в строке, которая специализируется на 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

4b9b3361

Ответ 1

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

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

// error, NOT valid!
template<> struct AClass<(int)> { X a; };

Я работал над этим (и, вероятно, увеличил его значение под капотом), передав имя типа в круглых скобках, а затем создав из него тип функции

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; 
};

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

Ответ 2

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);
}

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

Ответ 3

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

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

Таким образом, существуют 2 (технические) проблемы с кодом, который вы указали:

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

Есть препроцессоры/метапрограммирование шаблона, однако более простым решением является использование типа без запятых:

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

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

SPECIALIZE_ACLASS

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

Ответ 4

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

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

Ответ 5

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

typedef std::vector<int,std::allocator<int> > myTypeDef; 
specialize_AClass(myTypeDef) //works

Ответ 6

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

Что степень его знаний о С++.

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

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

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