如何组合生成唯一标识符的两个boost记录宏?

时间:2016-09-17 20:32:47

标签: c++ boost macros boost-log

我正在使用boost_logging(版本2),我想避免在我的代码中乱扔垃圾:

public class CommonElements {
    ArrayList<String> commonCollections = new ArrayList<String>();

    private int comparisons = 0;
    int i, j, k;
    int count, lowestCount;
    String previousString = "";
    int row[];
    String current;

    public Comparable[] findCommonElements(Comparable[][] collections) {

        Arrays.sort(collections[0]);

        row = new int[collections[0].length];

        for (i = 0; i < collections[0].length; i++) { // first row column selection
            current = collections[0][i].toString();
            lowestCount = 1;
            for (j = 0; j < collections.length; j++) { // row
                count = 0;
                for (k = 0; k < collections[0].length; k++) { // column
                    if (current.equals(collections[j][k].toString())) { // if contains same string as first row column selected
                        count++;
                        System.out.print(count + "\n");
                    }
                }
                if (lowestCount < count) {
                    lowestCount = count;
                }
            }
        }

        System.out.print(lowestCount);

        return collections[0];
    }

    public int getComparisons() {
        return comparisons;
    }


}

我想到的第二点是,我更喜欢将它们组合在一个像这样的宏中:

BOOST_LOG_NAMED_SCOPE("SomeModuleName")
BOOST_LOG_FUNCTION()

但是当我尝试这样做时,我收到了一个错误。见下文。

对于允许我在模块级别执行#define LOG_NAMED_SCOPE_FUNCTION(name)\ BOOST_LOG_NAMED_SCOPE(name)\ BOOST_LOG_FUNCTION() 之类的操作(也会出错),我会非常满意。更好的是一个解决方案,可以做某种RAII / AOP,让我也可以追加&#34;输入&#34;和&#34;退出&#34;在函数的开头和结尾跟踪消息,因为这是我的最终目标。

我在猜测,因为生成的唯一标识符在宏定义时扩展,而不是在宏调用时扩展。我还看了DEFERRED和EXPAND助手,但我不确定他们是否会在这里帮助我。

以下是错误消息:

BOOST_LOG_NAMED_SCOPE("SomeModuleName")

1 个答案:

答案 0 :(得分:1)

您遇到的问题是因为BOOST_LOG_FUNCTION基本上基于BOOST_LOG_NAMED_SCOPE - 它添加了一个范围,其名称对应于当前的函数签名。这两个宏都创建一个局部变量,该名称对于源文件的给定行是唯一的(它使用__LINE__来生成该名称)。根据C / C ++预处理器规则,所有宏都扩展为一行,因此LOG_NAMED_SCOPE_FUNCTION扩展为同一范围内的两个相同的命名局部变量,因此编译器错误。

解决此问题的一种方法是定义宏,以便它直接为两个范围定义两个不同的变量。变量应该具有named_scope::sentry类型,这是一个范围保护,在构造和销毁时自动将范围推送并弹出到堆栈。

#define LOG_NAMED_SCOPE_FUNCTION(name)\
    boost::log::attributes::named_scope::sentry BOOST_LOG_UNIQUE_IDENTIFIER_NAME(scope_sentry1_)(name, __FILE__, __LINE__);\
    boost::log::attributes::named_scope::sentry BOOST_LOG_UNIQUE_IDENTIFIER_NAME(scope_sentry2_)(BOOST_CURRENT_FUNCTION, __FILE__, __LINE__, boost::log::attributes::named_scope_entry::function)

这样每个LOG_NAMED_SCOPE_FUNCTION都会将两个范围添加到列表中 - 命名范围和当前函数。

但是,根据您的描述,它看起来并不是您想要实现的目标。 Boost.Log不允许直接使用它们所源自的模块的名称来标记日志记录 - 主要是因为没有可移植的方式来了解它,并且非便携方式很昂贵。但有一些方法可以模仿这种行为。以下是一些想法。

最简单的方法是使用您自己的日志记录宏,它将自动添加当前模块名称属性。

// Define the attribute keyword for the module name
BOOST_LOG_ATTRIBUTE_KEYWORD(a_module, "Module", std::string)

#define MY_LOG(lg)\
    BOOST_LOG(lg) << boost::log::add_value(a_module, CURRENT_MODULE)

如果将CURRENT_MODULE定义为在项目设置中命名当前模块的字符串,MY_LOG宏将自动将其作为属性附加到记录中。请参阅有关attribute keywordsadd_value manipulator的文档。

另一种方法是使用channels。如果不同模块共享记录器,则可以将当前模块名称设置为通道名称。或者,如果您已经使用了频道,请将其作为新的单独属性添加到您创建的每个记录器中。您可以编写自己的logger feature来自动执行该操作。

如果您确实共享记录器,那么您还可以查看scoped attributes的实施方式,尤其是BOOST_LOG_SCOPED_THREAD_TAG。由于您可能在不同模块之间调用函数,BOOST_LOG_SCOPED_THREAD_TAG将不适合您(因为如果已经存在,它将不会替换集合中的属性 - 在您的情况下,这意味着您将只看到首先设置属性的模块的名称,但您可以实现类似于适合您的情况的类似的东西。我们的想法是将当前模块名称添加为特定于线程的属性(如果没有添加或替换现有的模块名称)。这必须在范围保护中完成,该范围保护必须在可以从其他模块调用的每个功能中使用。