C11 / C ++ 11宏将常量字符串与文字整数相关联

时间:2016-03-21 16:13:44

标签: c++ string c++11 enums

我已经拥有一大堆C ++源代码文件,其中包含对以这种方式编写的记录器函数的调用:

LogIx(_S("This is my msg"));

其中:

#define _S(a)  (#a)

它有效,但我的客户想投入生产不易理解的记录器(我不太同意,但无论如何......)。源代码库非常大,所以我的想法是尽可能少地修改并将数字(索引)与每条消息相关联,并将所有消息放在一个表中,以便该数字将成为表中消息的索引。 / p>

第一个想法(有效)是查找所有_S(...)消息,从源中提取它们并用它们的等价物填充枚举,然后用enum标记更改每个_S()内的参数。当然,它不容易出错,并且在将来添加其他消息时也不是很好。

所以我正在考虑使用预处理器的不同解决方案,但似乎不可能在#define中使用带引号的字符串。

这段C ++源代码不起作用,但展示了我想做的事情:

#define _V(a)  (#a)

const std::array<string, 3> s_logStrings = {
      _V("This is my msg"),
      _V("Param %s is: %d"),
      _V("Reset msg")
};

#define _S("This is my msg")   0
#define _S("Param %s is: %d")  1
#define _S("Reset msg")        2

int Log(size_t msgIndex)
{
   cout << s_logStrings.at(LogIx(msgIndex));
}

int main(void)
{
   std::cout << "Begin test" << std::endl;
   Log(_S("This is my msg"));
   std::cout << "End test" << std::endl;

   return 0;
}

#define _V(a)  (#a)

const std::array<string, 3> s_logStrings = {
      _V("This is my msg"),
      _V("Param %s is: %d"),
      _V("Reset msg")
};

#define _S(a) // ???? this is the problem... how define this macro?
// also a constexpr could be a good solution, the point is to don't
// add a function or a <map>

#define _S("This is my msg")   0
#define _S("Param %s is: %d")  1
#define _S("Reset msg")        2

int Log(size_t msgIndex)
{
   cout << s_logStrings.at(msgIndex);
}

int main(void)
{
   std::cout << "Begin test" << std::endl;
   Log(_S("This is my msg"));
   std::cout << "End test" << std::endl;

   return 0;
}

任何想法或建议都将受到赞赏。

1 个答案:

答案 0 :(得分:0)

将您的文字转换为char_sequence, 你可以这样做:

template <char ... > struct char_sequence {};

// use gnu extension :/
template<class CharT, CharT... cs>
char_sequence<cs...> operator ""_seq(){
    return {};
}

template <class T, class Tuple>
struct index_in_tuple;

template <class T, class... Types>
struct index_in_tuple<T, std::tuple<T, Types...>> {
    static const std::size_t value = 0;
};

template <class T, class U, class... Types>
struct index_in_tuple<T, std::tuple<U, Types...>> {
    static const std::size_t value = 1 + index_in_tuple<T, std::tuple<Types...>>::value;
};

using MyMessagesTuple = decltype(std::make_tuple(
    "This is my msg"_seq,
    "Param %s is: %d"_seq,
    "Reset msg"_seq
));


#define _S(a)  (index_in_tuple<decltype(a##_seq), MyMessagesTuple>::value)

int main() {
    auto foo = _S("Reset msg");
    std::cout << foo << std::endl;
}

Demo