【问题标题】:Conditional Compilation Based on Type of #define variables基于#define变量类型的条件编译
【发布时间】:2019-06-19 07:15:09
【问题描述】:

以下是我想要实现的剪辑版本。我正在对一个单词进行一些算术运算,我想在可用时使用__builtin_clrsb,并且用户使用int 作为单词类型,否则使用慢速算法编译。以下使用 __builtin_clrsb 编译,无论 WORD 类型如何。

代码使用 C++11,但在嵌入式系统上运行,因此我无法访问大部分 std:: 设施。

#if !defined(WORD)
  #define WORD int
#endif

template<size_t S, typename word = WORD>
class my_class {
  ...
  ...
  ...

  size_t do_stuff(){
#if WORD == int && defined(__builtin_clrsb)
    //compile with  __builtin_clrsb
#else
   //comple with slow method
#endif
  }
};

【问题讨论】:

  • 你只能使用文字来#defineint是关键字。您的编译器是否返回错误?
  • @dunajski 如果您在谈论#define WORD int,那是有效的:宏名称是WORD,并且宏定义可以指定任何有效标记序列,而不仅仅是文字。 (#if WORD == int ... 不是。)
  • @dunajski 没有错误,但 WORD == int 总是正确的。
  • @HamzaYerlikaya aschelper,哎呀我不知道这个宏是有效的,我的错。
  • 使用部分模板特化。见这里en.cppreference.com/w/cpp/language/partial_specialization

标签: c++11 gcc clang c-preprocessor


【解决方案1】:

我认为你不应该这样做:

  size_t do_stuff(){
#if WORD == int && defined(__builtin_clrsb)
    //compile with  __builtin_clrsb
#else
    //comple with slow method
#endif
  }

您应该使用 C++ 模板专业化来解决这个问题。

template<class D, size_t S, class word>
struct my_class_do_stuff_impl {
  D& self() { return *static_cast<D*>(this); }
  D const& self() const { return *static_cast<D const*>(this); }
  size_t do_stuff(){
    //compile with slow method
    //use `self()` instead of `this` to access members of `my_class`
  }
};
#if defined(__builtin_clrsb)
  template<class D, size_t S>
  struct my_class_do_stuff_impl<D,S,int> {
    D& self() { return *static_cast<D*>(this); }
    D const& self() const { return *static_cast<D const*>(this); }
    size_t do_stuff(){
      //compile with  __builtin_clrsb
      //use `self()` instead of `this` to access members of `my_class`
    }
  };
#endif
template<size_t S, typename word = WORD>
class my_class:
  public my_class_do_stuff_impl<my_class<S,word>, S, word>
{
  // don't include do_stuff here
  // if you call do_stuff, do this->do_stuff()
};

这样做的理由有很多。一是WORD 是 int 不会强制 my_class 的 wordint。另一个是我们可以在预处理器之外执行此操作,所以我们应该这样做。

【讨论】:

  • 虽然__builtin_clrsb 可能根本不为预处理器或编译器所知,但在这种情况下使用它的do_stuff 是无效的,除非它仅用作从属名称,这听起来不太可能。也许这可以与一些预处理器工作一起很好地工作。
  • @aschepler 是的,该符号可能仅在 WORDint 或类似时才存在?在这种情况下,希望有不同于WORDint 的东西可以区分它的存在。
  • 原版确实有&amp;&amp; defined(__builtin_clrsb)。调整这一点并不难,以便在没有这样的宏时使用“慢”实现(不管 WORD 是什么),但我认为它看起来并不完全相同。
  • @aschepler 好点。然后轻松修复。解决了,看起来完全一样(嗯,一个额外的#if 围绕一个专业化)
  • 哦,对了,整个专业。是的,这比我想的要简单得多。
【解决方案2】:

问题

#if WORD == int && defined(__builtin_clrsb)

除了 == 在 C++ 中处理值而不是类型的事实之外,#if 在预处理步骤而不是编译期间被评估,并且预处理器并不真正知道 int 是什么。 #if 的规则是,在替换所有宏并评估所有defined() 测试之后,除true 之外的每个标识符类标记,甚至是没有命名宏的 C++ 关键字,都按顺序更改为0评估#if

所以在用其他类型替换WORD(比如说short)并将defined评估为1之后,预处理器就剩下了

#if short == int && 1

然后关键字变成0:

#if 0 == 0 && 1

这是真的。

我推荐Yakk's answer中显示的模板解决方案。


[但万一有人关心,在我看到那个答案之前,这里有一个基于预处理器的 hack。仅当WORD 不包含long long 之类的空格时才有效。]

#define PP_CONCAT1(x,y) x ## y
#define PP_CONCAT(x,y) PP_CONCAT1(x,y)
#define PP_IS_INT_int 1
#define PP_IS_INT_signed 1 /* "signed" alone is the same type as "int" */
#if PP_CONCAT(PP_IS_INT_, WORD) && defined(__builtin_clrsb)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-24
    • 1970-01-01
    • 2018-05-18
    相关资源
    最近更新 更多