C ++ вложенные направления препроцессора - PullRequest
0 голосов
/ 26 сентября 2011

Я использую директивы препроцессора для удаления некоторых шаблонных определений операторов. Э.Г.

#define BINARY_VECTOR_RETURN_OPERATOR(optype)   \
template <typename T, typename U> \
vector<decltype(T() optype U())> operator optype (const vector<T>& A, const vector<U>& B){ \
  vector<decltype(T()*U())> C; \
  C.reserve(A.size()); \
  typename vector<T>::const_iterator a = A.begin(); \
  typename vector<U>::const_iterator b = B.begin(); \
  while (a!=A.end()){ \
    C.push_back((*a) optype (*b)); \
    ++a; ++b; \
  } \
  return C; \
} \

BINARY_VECTOR_RETURN_OPERATOR(*);
BINARY_VECTOR_RETURN_OPERATOR(+);
BINARY_VECTOR_RETURN_OPERATOR(-);
BINARY_VECTOR_RETURN_OPERATOR(%);

Так что это прекрасно работает. Теперь я хочу иметь два режима работы: «отладка» и «не отладка», которые я установил с помощью команды #define DEBUG ранее. Я хотел бы сделать что-то вроде этого:

#define BINARY_VECTOR_RETURN_OPERATOR(optype)   \
template <typename T, typename U> \
vector<decltype(T() optype U())> operator optype (const vector<T>& A, const vector<U>& B){ \
  #ifdef DEBUG
  uint n = A.size();    \
  if (n != B.size()){ \
    char buf[BUFFLEN]; \
    sprintf(buf, "Size mismatch in operator+(%s,%s), sizes: (%d, %d), crashing!", \
        typeid(A).name(), typeid(B).name(), (int) A.size(), (int) B.size()); \
    cout << buf << endl; \
    throw("Size Mismatch Error"); \
    } \
  #endif
  vector<decltype(T()*U())> C; \
  C.reserve(A.size()); \
  typename vector<T>::const_iterator a = A.begin(); \
  typename vector<U>::const_iterator b = B.begin(); \
  while (a!=A.end()){ \
    C.push_back((*a) optype (*b)); \
    ++a; ++b; \
  } \
  return C; \
} \

но компилятору это не нравится. Я мог бы переопределить весь BINARY_VECTOR_RETURN_OPERATOR для каждого случая, используя #ifdef DEBUG, но это не очень элегантно. Есть ли способ реализовать код в духе моего второго примера?

Ответы [ 4 ]

2 голосов
/ 26 сентября 2011

Вы не можете иметь #if внутри #define, но вы можете иметь #define внутри кода, управляемого #if.

Например:

#ifdef DEBUG

#define BINARY_VECTOR_RETURN_OPERATOR(optype) \
first-part \
debug-code \
last-part

#else

#define BINARY_VECTOR_RETURN_OPERATOR(optype) \
first-part \
last-part

#endif

Если первая часть и последняя часть достаточно велики, вы можете определить макросы для них.

Я не говорю, что это хорошая идея, но она делает то, что вы пытались сделать.

РЕДАКТИРОВАТЬ : Спасибо @ okorz001 за предложение более чистой альтернативы в комментарии:

#ifdef DEBUG
#define DEBUG_CODE (blah, blah)
#else
#define DEBUG_CODE /* nothing */
#endif

#define BINARY_VECTOR_RETURN_OPERATOR(optype) \
first-part \
DEBUG_CODE;
last-part

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

2 голосов
/ 26 сентября 2011

Тьфу, старайся никогда не использовать препроцессор для реального кода.Это почти всегда очень плохая идея.

Я реструктурировал макрос как шаблонную функцию.Я повеселился с типами decltypes, так что я вытащил класс черт, чтобы уменьшить сложность определения функции!

Я не вижу способа полностью избавиться от макросапросто для здравомыслия в декларации фактических перегрузок операторов.Теперь, однако, это всего лишь простой переход к шаблонной функции operator_impl (), и в этом вы сможете использовать #ifdefs для своего кода отладки.

template <typename T, typename U, typename Op>
struct op_result
{
    typedef vector<decltype( (*((Op*)nullptr)) (*(T*)nullptr, *(U*)nullptr) ) > type;
};

template <typename T, typename U, typename Op>
inline typename op_result<T, U, Op>::type
operator_impl(const vector<T>& A, const vector<U>& B, Op op)
{
    op_result<T, U, Op>::type C;
    C.reserve(A.size());
    typename vector<T>::const_iterator a = A.begin();
    typename vector<U>::const_iterator b = B.begin();
    while (a!=A.end())
    {
        C.push_back(op(*a, *b));
        ++a; ++b;
    }
    return C;
}

#define BINARY_VECTOR_RETURN_OPERATOR(optype) \
template <class T, class U> \
inline vector<decltype( *(const T*)nullptr optype *(const U*)nullptr)> \
operator optype (const vector<T>& A, const vector<U>& B) \
{ \
    return operator_impl(A, B, [](const T& t, const U& u) {return t optype u;}); \
}
1 голос
/ 26 сентября 2011

Работает ли assert или BOOST_ASSERT?(Должен признать, что я никогда раньше не вставлял утверждение в макрос - поэтому за кадром это может просто воспроизводить вашу проблему)

Итак, вместо

 #ifdef DEBUG
  uint n = A.size();    
  if (n != B.size()){ 
    char buf[BUFFLEN]; 
    sprintf(buf, "Size mismatch in operator+(%s,%s), sizes: (%d, %d), crashing!", 
        typeid(A).name(), typeid(B).name(), (int) A.size(), (int) B.size()); 
    cout << buf << endl; 
    throw("Size Mismatch Error"); 
    } 
  #endif

просто напишите

BOOST_ASSERT(A.size() == B.size());  //include  <boost/assert.hpp>

или

assert(A.size() == B.size());   //include <assert.h>

(Вот несколько пояснительных ссылок для boost assert и assert.h )

0 голосов
/ 26 сентября 2011

Может быть, есть способ реализовать код в духе вашего второго примера. Вы можете использовать if () вместо #ifdef, как это

// May not be useful but still...
#ifdef DEBUG 
#define DEBUG 1
#else
#define DEBUG 0
#endif


#define BINARY_VECTOR_RETURN_OPERATOR(optype) \
template <typename T, typename U> \
 // Code within #ifdef.........    \
  if(DEBUG) {               \
      uint n = A.size();    \
      // .............      \
  }// end if \
 // Code after #ifdef.................. \
vector<decltype(T()*U())> C;\
return C; \
} \

Пожалуйста, проверьте и посмотрите, работает ли это.

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