C++嵌套预处理器方向

发布于 2024-12-06 13:36:01 字数 1758 浏览 0 评论 0原文

我正在使用预处理器指令来消除某些模板化运算符定义的膨胀。例如

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

但编译器似乎不喜欢那样。我可以使用 #ifdef DEBUG 围绕整个事情重新定义整个 BINARY_VECTOR_RETURN_OPERATOR ,但这不是很优雅。有没有办法按照我的第二个示例的精神来实现代码?

I'm using preprocessor directives to de-bloat some templated operator definitions. E.g.

#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(%);

So that works fine. What I want to do now is to have two modes of operation, "debug" and "not debug" which I set via a #define DEBUG command earlier. I would like to do something like this:

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

but the compiler doesn't seem to like that. I could redefine the entire BINARY_VECTOR_RETURN_OPERATOR for each case using #ifdef DEBUG around the whole thing, but that's not very elegant. Is there a way to implement the code in the spirit of my second example?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

み青杉依旧 2024-12-13 13:36:01

#define 中不能包含 #if,但可以在 控制的代码中包含 #define #如果。

例如:

#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

显然真正的代码会使用更好的名称。

You can't have a #if inside a #define, but you can have a #define inside the code controlled by a #if.

For example:

#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

If first-part and last-part are big enough, you might want to define macros for them.

I'm not saying this is a good idea, but it does do what you were trying to do.

EDIT: Thanks to @okorz001 for suggesting a cleaner alternative in a comment:

#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

Obviously the real code would use better names.

最冷一天 2024-12-13 13:36:01

呃,尽量不要将预处理器用于实际代码。这几乎总是一个非常糟糕的主意。

我尝试将宏重组为模板函数。我对 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;}); \
}

Ugh, try not to ever use the preprocessor for actual code. It's almost always a really bad idea.

I had a go at restructuring the macro as a template function. I had some fun with the decltypes, so much so that I pulled out a traits class just to reduce the complexity of the function definition!

I don't really see a way of getting rid of the macro completely, just for sanity in the declaration of the actual operator overloads. Now, however, it's just a simple pass-through to the template function operator_impl() and in that you should be able to use #ifdefs for your debug code.

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;}); \
}
柠檬色的秋千 2024-12-13 13:36:01

assertBOOST_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>

(这里有一些解释性链接 增强断言assert.h)

Does an assert or BOOST_ASSERT do the job? (Got to admit I have never put an assert in a macro before - so behind the scenes this might just be reproducing your problem)

So, instead of

 #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

just write

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

or

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

(Here are some explanitary links for boost assert and assert.h)

糖粟与秋泊 2024-12-13 13:36:01

可能有一种方法可以按照第二个示例的精神来实现代码。
您可以像这样使用 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; \
} \

请测试并查看这是否有效。

May be there is a way to implement the code in the spirit of your second example.
You can use if() instead of #ifdef like this

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

Please test and see if this works.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文