Redundant macro usage in initializer lists

问题内容:

After I were able to successfully reduce code duplication with this I want to further reduce my code duplication with totally different problem

#include <iostream>
#include <array>

#define NUM 5

#define A1
#define B2
#define C3
#define D4
#define E5

int main()
{
  std::array<const char*, NUM + 1> arr1{{
    #ifdef A1
      "1",
    #endif
    #ifdef B2
      "2",
    #endif
    #ifdef C3
      "3",
    #endif
    #ifdef D4
      "4",
    #endif
    #ifdef E5
      "5",
    #endif
      "26"
  }};
  std::array<const char*, NUM + 1> arr2{{
    #ifdef A1
      "a",
    #endif
    #ifdef B2
      "b",
    #endif
    #ifdef C3
      "c",
    #endif
    #ifdef D4
      "d",
    #endif
    #ifdef E5
      "e",
    #endif
      "z"
  }};
  for (const auto& str : arr1)
    std::cout << str << std::endl;
  for (const auto& str : arr2)
    std::cout << str << std::endl;
  std::cout << "ok" << std::endl;
  return 0;
}

In the code above I have two array and their values initialized with initialization list. The problem I want to address is the need to have #ifdef and #endif twice. Instead, I want to have some thing like

#define MACRO(index) \
    #ifdef A1 \
      "1" "a" \
    #endif \
    #ifdef B2 \
      "2" "b" \
    #endif \
    #ifdef C3 \
      "3" "c" \
    #endif \
    #ifdef D4 \
      "4" "d" \
    #endif \
    #ifdef E5 \
      "5" "e" \
    #endif \
      "26" "z"

std::array<const char*, NUM + 1> arr1{{ MACRO(1) }};
std::array<const char*, NUM + 1> arr2{{ MACRO(2) }};

Obviously, this code doesn’t work but can I write something in this spirit?

问题评论:

    
Can you use C++14?
    
Unfortunately no, I plan to move to c++14 and even c++17 in the future but currently I need to work with c++11
– e271p314
3 hours ago
    
What would be the difference between MACRO(1) and MACRO(2)? index is never used
    
are you really saving more duplicate code than you have to write duplicates of #ifdef / #endif ?
    
@VTT index is not used because I don’t know how to write this macro, I just know how I want to use it (similar/equivalent usage without index is also acceptable). @tobi303 indeed, code duplication is not the only concern, maintaining the mapping between arr1 and arr2 is also a big problem I would like address with this code
– e271p314
3 hours ago

答案:

答案1:

You might use pair/tuple to group data together:

std::array<std::pair<const char*, const char*>, NUM + 1> arr{{
#ifdef A1
    {"1", "a"},
#endif
#ifdef B2
    {"2", "b"},
#endif
#ifdef C3
    {"3", "c"},
#endif
#ifdef D4
    {"4", "d"},
#endif
#ifdef E5
    {"5", "e"},
#endif
    {"26", "z"}
}};
for (const auto& p : arr) {
    std::cout << p.first << std::endl;
}
for (const auto& str : arr) {
    std::cout << p.second << std::endl;
}
std::cout << "ok" << std::endl;

答案评论:

    
Yes you are right, but the real code has a macro that that takes an unknown amount of arguments and an array (that uses this marco to know its size). I can’t use an array of pairs because I have to completely different types
– e271p314
2 hours ago

答案2:

Create one array:

using arr_type=char const[];
#define ARRAY_SOURCE = arr_type{ "1", "a", "2", "b", /* etc */ }

use #ifdef to define indexes.

// elements.inc:
#ifdef A
ARRAY_SOURCE[0+OFFSET],
#endif
// etc

then

std::array<const char*, NUM + 1> arr1{{
#define OFFSET 0
#include "elements.inc"
#undef OFFSET
}};
std::array<const char*, NUM + 1> arr2{{
#define OFFSET 1
#include "elements.inc"
#undef OFFSET
}};

答案评论:

    
I like this direction, but two things I would like to avoid the need to have elements.inc, I would like to have all declaration in the same header file, and the need to bind “a” and “1” to index 0 (as in your example of elements.inc)
– e271p314
2 hours ago

原文地址:

https://stackoverflow.com/questions/47752997/redundant-macro-usage-in-initializer-lists

添加评论