打印宏观值而不知道宏的数量

Print macro values without knowing the amount of macros

本文关键字:不知道 宏观 打印      更新时间:2023-10-16

我有包括生成文件的代码(我不提前知道其内容),我和我的用户在上面有一个约定,我和我的用户同意如何创建此文件,以便我可以使用它。这个文件看起来像

#define MACRO0 "A"
#define MACRO1 "B"
#define MACRO2 "C"
...

我想打印所有宏值。我当前的代码看起来像

#ifdef MACRO0
std::cout << "MACRO0 " << MACRO0 << std::endl;
#endif
#ifdef MACRO1
std::cout << "MACRO1 " << MACRO1 << std::endl;
#endif
#ifdef MACRO2
std::cout << "MACRO2 " << MACRO2 << std::endl;
#endif

我的问题是,如何迭代生成的文件中的宏,因此我不需要重复我的代码太多

首先,我们知道我们可以依靠boost.prepropessor来满足我们的循环需求。但是,生成的代码必须自行起作用。不幸的是,#ifdef无法由于宏扩展而起作用,因此无法在问题中生成代码。我们烤了吗?

还没有!我们可以利用您的宏都是不存在或字符串字面的事实。考虑以下内容:

using StrPtr = char const *;
StrPtr probe(StrPtr(MACRO1));

我们正在利用我们的老朋友在这里最烦人的解析。第二行可以通过两种方式来解释,具体取决于是否定义了MACRO1。没有它,它等同于:

char const *probe(char const *MACRO1);

...这是 MACRO1是参数名称的函数声明。但是,当将MACRO1定义为"B"时,它等同于:

char const *probe = (char const *) "B";

...这是一个初始化为"B"的变量。然后,我们可以打开我们刚刚产生的类型,以查看是否发生了替代:

if(!std::is_function<decltype(probe)>::value)
    std::cout << "MACRO1 " << probe << 'n';

我们可以在此处使用if constexpr,但是std::cout可以输出功能指针(将其转换为bool),因此死亡分支是有效的,并且编译器足够聪明,可以完全对其进行优化。

最后,我们回到boost.preprocessor为我们生成所有这些东西:

#define PRINT_IF_DEFINED(z, n, data) 
    { 
        StrPtr probe(StrPtr(BOOST_PP_CAT(MACRO, n))); 
        if(!std::is_function<decltype(probe)>::value) 
            std::cout << "MACRO" BOOST_PP_STRINGIZE(n) " " << probe << 'n'; 
    }
#define PRINT_MACROS(num) 
    do { 
    using StrPtr = char const *; 
    BOOST_PP_REPEAT(num, PRINT_IF_DEFINED, ~) 
    } while(false)

...voilà!

看到它活在coliru

注意:COLIRU片段包括GCC和Clang的警告残疾人,警告我们可怜的PAL最令人沮丧的解析:(

我很久以前就遇到了相同的需求。

我的解决方案是使用预处理器,但不要获得"代码中的答案"。

例如,clang++ -dM -E test.cpp将输出所有宏。(当时,我使用了gcc,但是相同的技术适用于GCC,Clang和Visual Studio的Cl.exe ...编译器开关可能会有所不同。)

ahh,drat,还包括所有预定义的宏。

因此,我会生成我不在乎的预定义宏的"黑名单"文件,然后使用它来过滤这些结果(使用grep -v)。

我遇到的另一个问题是,有时有人会 #undef IMPORTANT_MACRO,然后在转储中被错过。对于那些不常见的情况... ,然后谋杀开始

此答案是书面的,考虑了后续问题。

c 具有对通用编程的支持,通常会消除对预处理器的需求。在这种情况下,最好制作一组类型特征,声明需要处理的参数的属性,以减少预处理器到有条件汇编的作用(或者如果应该每次都应该生成此代码,则完全消除它):

enum class
t_Param
{
    begin, a = begin, b, c, d, e, z, end
};
template<t_Param param, typename TEnabled = void> class
t_ParamIsEnabled final: public ::std::true_type
{};
template<t_Param param> class
t_ParamIsEnabled
<
    param
,   typename ::std::enable_if
    <
        (t_Param::end == param)
        #ifndef A1
        || (t_Param::a == param)
        #endif
        #ifndef B2
        || (t_Param::b == param)
        #endif
        #ifndef C3
        || (t_Param::c == param)
        #endif
        #ifndef D4
        || (t_Param::d == param)
        #endif
        #ifndef E5
        || (t_Param::e == param)
        #endif
    >::type
> final: public ::std::false_type
{};
template<t_Param param> class
t_ParamTrait;
template<> class
t_ParamTrait<t_Param::a> final
{
    public: static constexpr auto const & num{"1"};
    public: static constexpr auto const & val{"A"};
};
template<> class
t_ParamTrait<t_Param::b> final
{
    public: static constexpr auto const & num{"2"};
    public: static constexpr auto const & val{"B"};
};
template<> class
t_ParamTrait<t_Param::c> final
{
    public: static constexpr auto const & num{"3"};
    public: static constexpr auto const & val{"C"};
};
template<> class
t_ParamTrait<t_Param::d> final
{
    public: static constexpr auto const & num{"4"};
    public: static constexpr auto const & val{"D"};
};
template<> class
t_ParamTrait<t_Param::e> final
{
    public: static constexpr auto const & num{"5"};
    public: static constexpr auto const & val{"E"};
};
template<> class
t_ParamTrait<t_Param::z> final
{
    public: static constexpr auto const & num{"26"};
    public: static constexpr auto const & val{"ZZ"};
};

这将允许您使用通用代码迭代参数并查询其属性:

template<t_Param param> typename ::std::enable_if<t_ParamIsEnabled<param>::value>::type
Echo(void)
{
    ::std::cout << t_ParamTrait<param>::val << ":" << t_ParamTrait<param>::num << ::std::endl;
}
template<t_Param param> typename ::std::enable_if<!t_ParamIsEnabled<param>::value>::type
Echo(void)
{
    //  Do nothing
}
template<int param_index = 0> void
Echo_All(void)
{
    Echo<static_cast<t_Param>(param_index)>();
    Echo_All<param_index + 1>();
}
template<> void
Echo_All<static_cast<int>(t_Param::end)>(void)
{
    //  Do nothing.
}
int main()
{
    Echo_All();
    return 0;
}

在线编译器