将一个char数组传递给函数模板,这样gcc就可以判断出它是一个字面量

Pass a char array to a function template such that gcc can tell it is a literal?

本文关键字:一个 判断 就可以 gcc 函数模板 数组 char 这样      更新时间:2023-10-16

我正在尝试将gcc的对printf格式字符串的编译时检查与c++11的可变模板包结合起来。

我知道我可以用gcc的__attribute__((format(__printf__, ...))装饰器装饰一个可变函数。

我知道我可以将可变变量模板包扩展为可变变量函数。例:printf(fmt, pack...);

是否有可能将两者结合起来?

在这个问题中,公认的答案指出gcc需要字量才能进行格式检查。

在下面的例子中,一个const char array被传递给可变函数和可变函数模板。当main中调用check时,gcc可以告诉它是字面量,但不能从check_t中调用

是否有任何方法将fmt字符串传递给check_t,使gcc将其视为字面量?

我想要实现的工作示例:

#include <iostream>
void check(const char*, ...) __attribute__((format(__printf__, 1, 2)));
void check(const char*, ...)
{ 
    // exists only for the purposes of catching bogus format strings
}
template<typename... Ts>
void check_t(const char fmt[], Ts... ts)
{
    // check the format string by expanding ts into the check function
    check(fmt, ts...);
}
int main()
{
    const char f[] = "foo %s";
    check_t(f, 5);              // compiles
    check(f, 5);                // fails to compile
    return 0;
}

您可以在模板参数中传递c-string:

template<const char* fmt, typename... Ts>
void check_t(Ts... ts)
{
    // check the format string by expanding ts into the check function
    check(fmt, ts...);
}
constexpr const char f[] = "foo %s";
int main()
{
    check_t<f>(5); // fails to compile
    //check(f, 5); // fails to compile
    return 0;
}

生活例子

如注释所述,在函数模板中不可能区分字符串字面值和字符数组,除非它是模板形参。

因此,在中利用gcc的__attribute__((format(__printf__, ...))语法从中获得可变函数模板是不可能的(除非格式字符串是模板参数而不是函数参数,如@Jarod42的回答)。

这种行为很容易让人想起日志框架——你既想要可变模板的类型安全,又想要格式字符串的编译时检查。

解决方法:使用逗号操作符

虽然这不是对特定问题的解决方案,但它是一种变通方法,可以使两者兼得。

它使用逗号操作符,特别是在链接文章中描述的例子:

i = (a, b); // discards a, stores b into i 

因此宏变成这样:

#define CHECK_T(fmt, ...) ( check(fmt, __VA_ARGS__), check_t(fmt, __VA_ARGS__) )
                                       ^           ^              ^
                                       |           |              |
    calls variadic function `check` ---+           |              |
                                                   |              |
    comma operator discards 1st operand -----------+              |
                                                                  |
    returns result of variadic function template `check_t` -------+

即使check调用将在编译期间使格式字符串无效,我的假设是它实际上将从二进制的发布版本中编译出来,因为它是一个空函数,只留下check_t调用进行实际的日志记录。