【问题标题】:C++ Meta-programmingC++ 元编程
【发布时间】:2013-10-07 02:32:33
【问题描述】:

C++我的项目开发过程中,我经常需要调试,我通常使用这个宏来做它

#define DBUG(a) {std::cout << #a << " : " << a << std::endl;};

但很多时候我需要做这样的事情

int a;
std :: string b;
double c;
...
...
DBG(a); DBG(b); DBG(c);

但理想情况下,可能只写DBUG(a, b, c)DBG(a, b, c, d, e) 以获得更多变量来实现这样的目标。经过一些研究,这看起来像是元编程或更具体的代码生成中的一个问题,但由于我在这些领域的知识有限,我找不到解决方法。

如果可能,我想在不使用 Boost 或其他外部库的情况下解决此问题,并使用 C++98 中的功能,但如果不可能,我愿意使用 C++11

【问题讨论】:

  • 这个问题的标题有点模糊,如果你有更好的想法,请编辑它。
  • Google 获取可变参数宏,这应该可以帮助您(并避免 endl,可能会通过使用预处理器连接字符串来减少对 operator&lt;&lt; 的调用次数......)
  • 是否可以使用可变参数宏来做类似#define DBUG1(...) DBUG(arg1);DBUG(arg2);...;DBUG(argk); 的事情
  • 为什么不使用调试器?它们非常擅长显示变量的值。
  • 没错,我可以使用gdb,但我更喜欢老式的打印变量的方式来调试。两者各有利弊。

标签: c++ templates macros metaprogramming


【解决方案1】:

我不喜欢对特定数量的参数进行限制。我没有找到一种静态解码名称的好方法,因此将名称作为逗号分隔的字符串放在一起,然后在运行时解码。总体而言,这可能有点过于繁重,但至少,它按照要求进行,并且对参数的数量没有限制(即编译器限制除外):

#include <iostream>
#include <sstream>
#include <iterator>
#include <algorithm>
#include <tuple>
#include <vector>
#include <type_traits>
#include <stdlib.h>

template <int I, int S, typename... V>
typename std::enable_if<I == S>::type
debug_var(std::vector<std::string> const&, std::tuple<V...> const&)
{
}

template <int I, int S, typename... V>
typename std::enable_if<I != S>::type
debug_var(std::vector<std::string> const& n, std::tuple<V...> const& v)
{
    std::cout << n[I] << '=' << std::get<I>(v) << ' ';
    debug_var<I + 1, S>(n, v);
}

template <typename... V>
void debug(std::vector<std::string> const& n, std::tuple<V...> const& v)
{
    debug_var<0, sizeof...(V)>(n, v);
    std::cout << '\n' << std::flush;
}

std::vector<std::string> debug_names(char const* names)
{
    std::vector<std::string> result;
    std::istringstream in(names);
    for (std::string name; std::getline(in >> std::ws, name, ','); ) {
        result.push_back(name);
    }
    return result;
}

#define DEBUG(...) debug(debug_names(#__VA_ARGS__), std::tie(__VA_ARGS__));

int main()
{
    int a=1, b=2;
    DEBUG(a, b);
    DEBUG();
}

代码使用了 2011 年 C++ 修订版引入的几个功能。

【讨论】:

  • 太棒了!聪明地使用宏和模板,虽然我将不得不花更多的时间来完全理解代码。可能还需要提到这仅适用于C++11
  • 如果你问我出色的运行时解决方案。现在我想知道是否可以在编译时使用其中一个编译时字符串库来处理名称。
【解决方案2】:

这是改编自 this answer 的一种解决方案。您必须通过更改CHOOSERDBG 宏以及添加适当的DBG# 宏来定义宏以支持最大数量的参数。它也需要 C++11。

#include <iostream>

#define DBG1(a) std::cout << #a ": " << a << "\n"
#define DBG2(a, b) DBG1(a); DBG1(b)
#define DBG3(a, b, c) DBG2(a, b); DBG1(c)

#define CHOOSER(a, b, c, CHOICE, ...) CHOICE
#define DBG(...) CHOOSER(__VA_ARGS__, DBG3, DBG2, DBG1)(__VA_ARGS__)

int main() {
    int a{}, b{1}, c{5};
    DBG(a, b, c);
}

输出:

一个:0
乙:1
c: 5

【讨论】:

  • 是的,只要我向DBUG 宏提供最多三个参数,它就可以工作,是否有可能使它适用于任意数量的参数,例如DBUG(a, b, c, d, e)
  • @user2833292,除非你扩展宏定义(所以永远不要随意)。宏非常原始。不过,它也适用于小于最大值的任何数字。
  • 那么是否可以使用模板,我记得看过C++模板是图灵完备的。
  • @user2833292:图灵完备并不意味着能够找出您在参数中使用的变量/表达式的名称。
  • @DanielKO 好吧,我可能误解了,但是我们可以结合宏和模板来实现这一点。
【解决方案3】:

您可以通过以下方式使用自己的DBUG(a)

DBUG(a &lt;&lt; " " &lt;&lt; b &lt;&lt; " " &lt;&lt; c);

【讨论】:

    【解决方案4】:

    使用一些好的 ol' C++11 可变参数模板怎么样?

    #include <iostream>
    #include <sstream>
    #include <string>
    
    
    template <typename T>
    std::string make_string(const T& t)
    {
        std::ostringstream oss;
        oss << t;
        return oss.str();
    }
    
    template <typename Thead, typename ... Ttail>
    std::string make_string(const Thead& head, const Ttail& ... tail)
    {
        return make_string(head) + make_string(tail...);
    }
    
    void debug(const std::string& msg)
    {
        std::cout << "DEBUG: " << msg << std::endl;
    }
    
    void debug(void)
    {
        std::cout << "DEBUG!" << std::endl;
    }
    
    template <typename ... Targs>
    void debug(const Targs& ... args)
    {
        debug(make_string(args...));
    }
    
    
    
    int main(void)
    {
        int z;
        debug("We're gonna crash: ", &z, "!");
        debug();
        debug(3.14);
    }
    

    【讨论】:

    • 不执行 OP 要求的操作,打印变量的名称及其值。
    • 如果我们可以打印变量的名称就完美了。
    • 我的错。对此感到抱歉。
    猜你喜欢
    • 2017-04-13
    • 1970-01-01
    • 1970-01-01
    • 2011-03-27
    • 2013-04-21
    • 1970-01-01
    • 2015-12-03
    • 2011-11-10
    相关资源
    最近更新 更多