我的宏观有点顽皮

Is my macro a little bit too naughty?

本文关键字:宏观 我的      更新时间:2023-10-16

我做了一个宏。我担心这可能有点"太调皮",因为宏是邪恶的

这是没有宏的代码:

case SDLK_a:
    _buffer_.InsertAtCursor('a');
    _buffer_.MutableCursor().Right();
    break;

这是宏定义及其用法:

#define SDLK_KEY_CASE_MACRO(X, Y) 
{
case X: 
    _buffer_.InsertAtCursor(Y); 
    _buffer_.MutableCursor().Right(); 
    break;
}
SDLK_KEY_CASE_MACRO(SDLK_b, 'b');
SDLK_KEY_CASE_MACRO(SDLK_c, 'c');
SDLK_KEY_CASE_MACRO(SDLK_d, 'd');
SDLK_KEY_CASE_MACRO(SDLK_e, 'e');
SDLK_KEY_CASE_MACRO(SDLK_f, 'f');
SDLK_KEY_CASE_MACRO(SDLK_g, 'g');
SDLK_KEY_CASE_MACRO(SDLK_h, 'h');
SDLK_KEY_CASE_MACRO(SDLK_i, 'i');
SDLK_KEY_CASE_MACRO(SDLK_j, 'j');
SDLK_KEY_CASE_MACRO(SDLK_k, 'k');
SDLK_KEY_CASE_MACRO(SDLK_l, 'l');
SDLK_KEY_CASE_MACRO(SDLK_m, 'm');
SDLK_KEY_CASE_MACRO(SDLK_n, 'n');
SDLK_KEY_CASE_MACRO(SDLK_o, 'o');
SDLK_KEY_CASE_MACRO(SDLK_p, 'p');
SDLK_KEY_CASE_MACRO(SDLK_q, 'q');
SDLK_KEY_CASE_MACRO(SDLK_r, 'r');
SDLK_KEY_CASE_MACRO(SDLK_s, 's');
SDLK_KEY_CASE_MACRO(SDLK_t, 't');
SDLK_KEY_CASE_MACRO(SDLK_u, 'u');
SDLK_KEY_CASE_MACRO(SDLK_v, 'v');
SDLK_KEY_CASE_MACRO(SDLK_w, 'w');
SDLK_KEY_CASE_MACRO(SDLK_x, 'x');
SDLK_KEY_CASE_MACRO(SDLK_y, 'y');
SDLK_KEY_CASE_MACRO(SDLK_z, 'z');

显然,这为我节省了很多打字和许多代码。该代码还编译并运行正常。

  • 但是这宏观顽皮吗?(这可能会产生意外行为,还是我不应该在代码中使用此"作弊"的原因吗?(

像任何理智的系统一样, SDL_SCANCODE_A(aka SDLK_a(处于连续的整数范围内,并且一直以SDL_SCANCODE_Z为顺序。'a'通过'z'也是如此。

if( val >= SDLK_a && val <= SDLK_z ) {
  _buffer_.InsertAtCursor( 'a' + (val-SDLK_a) );
  _buffer_.MutableCursor().Right();
} else {
  // handle other cases
}

这比宏壁更高效,更短,更清晰。

您可能必须重复数字。

对于特殊字符(标签,引号等(,我不会依靠事物很好地出现。在那里您需要有一个短表

struct SDL_table {
  unsigned code; 
  char value;
};
SDL_table table[] = {
  {SDL_SCANCODE_TAB, 't'},
  // ... etc
};

然后,在较早的检查失败之后,快速搜索该表

auto it = std::find_if( std::begin(table), std::end(table), [&](SDL_table t) { return t.code == val; } );
if (it != std::end(table)) {
  _buffer_.InsertAtCursor( it->value );
  _buffer_.MutableCursor();
} else {
  // deal with unrecognized scancode
}

此时我可能会重构_buffer_代码。

char SDLK_to_char( unsigned sdlk ) {
  if( sdlk >= SDLK_a && sdlk <= SDLK_z )
     return 'a' + (val-SDLK_a);
  if( sdlk >= SDLK_0 && sdlk <= SDLK_9 )
     return '0' + (sdlk-SDLK_0);
  struct SDLK_entry {
    unsigned code; 
    char value;
  };
  static const SDLK_entry table[] = {
    {SDL_SCANCODE_TAB, 't'},
    // ... etc
  };
  auto it = std::find_if( std::begin(table), std::end(table),
   [&](auto&& t) { return t.code == sdlk; }
  );
  if (it != std::end(table))
    return it->value;
  return 0; // null for failure
}

然后

char c = SDLK_to_char( sdlk );
if (c) {
  _buffer_.InsertAtCursor( c );
  _buffer_.MutableCursor().Right();
}

好吧,我会避开宏 - 即使我必须用案例编写完整的 switch

,但首先我会考虑一种替代方法。

例如,查找表将SDLK_...转换为...。在C 中,您可以基于std::map

喜欢:

  std::map<SDLK_type, char> look_up_table = {{SDLK_a, 'a'}, {SDLK_b, 'b'}};
  auto i = look_up_table.find(SDLK_value);
  if (i != look_up_table.end())
  {
    char c = i->second;
    _buffer_.InsertAtCursor(c);
    _buffer_.MutableCursor().Right();
  }
  else
  {
    std::cout << "Not found" << std::endl;
  }