如何将Variadic Templates变成多个单模板?(C++编程竞赛调试模板)

How to turn Variadic Templates into multiple single templates?(C++ Competitive Programming Debugging Template)

我的调试模板是:

#define ts to_string 
string ts(char c) { return string(1, c); }
string ts(bool b) { return b ? "true" : "false"; }
string ts(const char* s) { return (string)s; }
string ts(string s) { return s; }
template<class A> string ts(complex<A> c) { 
    stringstream ss; ss << c; return ss.str(); }
string ts(vector<bool> v) { 
    string res = "{"; for(int i = 0; i < si(v); ++i) res += char('0' + v[i]);
    res += "}"; return res; }
template<size_t SZ> string ts(bitset<SZ> b) {
    string res = ""; for(int i = 0; i < SZ; ++i) res += char('0' + b[i]);
    return res; }
template<class A, class B> string ts(pair<A,B> p);
template<class T> string ts(T v) { // containers with begin(), end()
    bool fst = 1; string res = "{";
    for(const auto& x: v) {
        if (!fst) res += ", ";
        fst = 0; res += ts(x);
    }
    res += "}"; return res;
}
template<class A, class B> string ts(pair<A,B> p) {
    return "(" + ts(p.f) + ", " + ts(p.s) + ")"; }

void DBG() { cerr << "]" << endl; }
template<class H, class... T> void DBG(H h, T... t) {
    cerr << ts(h); if (sizeof...(t)) cerr << ", ";
    DBG(t...); }
#ifdef LOCAL // compile with -DLOCAL
#define dbg(...) cerr << "[" << #__VA_ARGS__ << "]: [", DBG(__VA_ARGS__)
#else
#define dbg(...) 0
#endif

当我打字时

dbg(a, n);

其中 'a' 是矢量名称,n 是矢量的大小。 'a' 包含以下 {1, 2, 3, 4, 5} 和 n = 5

它打印

[a, n]: [{1, 2, 3, 4, 5}, 5]

但我想要打印出来

[a]: [{1, 2, 3, 4, 5}]
[n]: [5]

无需输入

dbg(a);
dbg(n);

有什么办法吗?

When I type

    dbg(a, n);

I want it to print

    dbg(a);
    dbg(n);

Is there any way to do this?

根据参数数量重载宏并在重载中为每个参数调用回调。

// renamed from dbg
#define dbg_in(...) cerr << "[" << #__VA_ARGS__ << "]: [", DBG(__VA_ARGS__)

// overloads
#define dbg_1(_1) \
        dbg_in(_1)
#define dbg_2(_1,_2) \
        dbg_1(_1);dbg_in(_2)
#define dbg_3(_1,_2,_3) \
        dbg_2(_1,_2);dbg_in(_3)
// etc.
#define dbg_N(_1,_2,_3,_4,_5,_6,_7,_8,_9,N,...) \
        dbg_##N
#define dbg(...) \
        dbg_N(__VA_ARGS__,9,8,7,6,5,4,3,2,1)(__VA_ARGS__)

dbg(a, b);
// expands to: dbg_in(a);dbg_in(b);

Codeforces 社区帮助了我并告诉了我正确的解决方案。

#define ts to_string
string ts(char c) { return string(1, c); }
string ts(bool b) { return b ? "true" : "false"; }
string ts(const char* s) { return (string)s; }
string ts(string s) { return s; }
template<class A> string ts(complex<A> c) { 
    stringstream ss; ss << c; return ss.str(); }
string ts(vector<bool> v) { 
    string res = "{"; for(int i = 0; i < si(v); ++i) res += char('0' + v[i]);
    res += "}"; return res; }
template<size_t SZ> string ts(bitset<SZ> b) {
    string res = ""; for(int i = 0; i < SZ; ++i) res += char('0' + b[i]);
    return res; }
template<class A, class B> string ts(pair<A,B> p);
template<class T> string ts(T v) { // containers with begin(), end()
    bool fst = 1; string res = "{";
    for (const auto& x: v) {
        if (!fst) res += ", ";
        fst = 0; res += ts(x);
    }
    res += "}"; return res;
}
template<class A, class B> string ts(pair<A,B> p) {
    return "(" + ts(p.f) + ", " + ts(p.s) + ")"; }
 
// DEBUG
void DBG(string names) { string s = names; }
template<class H, class... T> void DBG(string names, H h, T... t) {
    auto pos = names.find(',');
    auto first_name = names.substr(0, pos);
    auto rest = names.substr(pos+1);
    // Strip space at the beginning
    while(rest.front() == ' '){
        rest = rest.substr(1);
    }
    cerr << "[" << first_name << "]: [" << ts(h) << "]" << nl;
    DBG(rest, t...);
}
#ifdef LOCAL
#define dbg(...) DBG(#__VA_ARGS__, __VA_ARGS__)
#else
#define dbg(...) 0
#endif
void EDBG() { cerr << "]" << endl; }
template<class H, class... T> void EDBG(H h, T... t) {
    cerr << ts(h); if (sizeof...(t)) cerr << ", ";
    EDBG(t...); }
#ifdef LOCAL // compile with -DLOCAL
#define edbg(...) cerr << "[" << #__VA_ARGS__ << "]: [", EDBG(__VA_ARGS__)
#else
#define edbg(...) 0
#endif

edbg

不单独做所以

edbg(a, n);

会输出

edbg(a, n);

鉴于

dbg(a, n);

会输出

dbg(a);
dbg(n);

问题是 #__VA_ARGS__ 不是 return 一个字符串列表,逗号分隔,变量名,而是一个字符串,变量名逗号分隔.

所以你必须以某种方式拆分字符串。

如果您可以使用 C++17,我建议使用以下函数,该函数采用单个字符串,名称以逗号分隔,并且 return 具有单个名称的 std::vector<std::string>

std::vector<std::string> splitWords (std::string const & s)
 {
   std::regex rgx ("\w+");

   return { std::sregex_token_iterator{s.begin(), s.end(), rgx},
            std::sregex_token_iterator{} };
 }

还有一个可变参数模板dbgh() (dbg helper) 函数如下

template <typename ... Ts>
void dbgh (std::vector<std::string> v, Ts const & ... ts)
 { 
   std::size_t i{};

   ((std::cerr << '[' << v[i++] << "]: [", DBG(ts)), ...);
 }

所以你可以这样写dbg()可变参数宏

#define dbg(...) dbgh(splitWords(#__VA_ARGS__), __VA_ARGS__)