【问题标题】:Combining function parameter pack and default arguments结合函数参数包和默认参数
【发布时间】:2020-09-24 17:27:56
【问题描述】:

我有一个带参数包的函数:

template<typename... Targs>
void tprintf(const char* format, Targs... args) {}

(实现无关紧要,只是签名)。我想使用 GCC/Clang 内置函数将源位置添加为默认参数。类似的东西

template<typename... Targs>
void tprintf(const char* format, Targs... args,
             const char* file = __builtin_FILE(),
             unsigned line = __builtin_LINE()) {}

这可以编译,但是对它的调用并没有像我希望的那样将参数传递给args;例如

tprintf("%d%s", 0, "a");

提供(在 Clang 10 上)

<source>:7:5: error: no matching function for call to 'tprintf'
    tprintf("%d%s", 0, "a");    
    ^~~~~~~
<source>:2:6: note: candidate function template not viable: no known conversion from 'const char [2]' to 'unsigned int' for 3rd argument
void tprintf(const char* format, Targs... args,    
     ^

这似乎表明args 是空的,0file"a"line

实际上,在编写问题时,我发现明确传递 Targs 有效:

tprintf<int, char*>("%d%s", 0, "a");

是否可以避免这种情况?

【问题讨论】:

标签: c++ variadic-templates variadic-functions parameter-pack


【解决方案1】:

解决方案是给我们 C++20 的 std::source_location:

#include <iostream>
#include <source_location>

template<typename... Targs, auto location = source_location::current()>
auto tprintf(char const* format, Targs const&... args) -> void {
    std::cout
        << std::format("{}:{}: ", location.file_name(), location.line())
        << std::format(format, args...);
}

auto main() -> int {
    tprintf("hello {}", "world"); // prints "example.cpp:12: hello world"
}

如果 C++20 不是一个选项(尤其是目前,编译器不支持源位置),那么有一种方法可以在没有宏的情况下进行。您可以简单地对编译器内置函数进行一些间接操作。

你不能将默认参数放在可变参数之后,但你可以将它们放在第一个参数的构造函数中以达到相同的效果:

#include <cstdio>

struct location_and_format {
    constexpr location_and_format(
        char const* _format,
        char const* _file_name = __builtin_FILE(),
        unsigned _line = __builtin_LINE()
    ) noexcept : format{_format}, file_name{_file_name}, line{_line} {}

    char const* format;
    char const* file_name;
    unsigned line;
};

template<typename... Targs>
void tprintf(location_and_format format, Targs... args) {
    printf("%s:%u: ", format.file_name, format.line);
    printf(format.format, args...);
}

int main() {
    tprintf("hello %s", "world"); // prints example.cpp:22: hello world
}

Live example

【讨论】:

    【解决方案2】:

    使用可变参数宏怎么样?

    template<typename... Targs>
    void tprintfhelper(const char* f, int l, const char* format, Targs... ) 
    {
        std::cout << format << " " << l << " " << f << std::endl;
    }
    
    #define tprintf(...) tprintfhelper(__builtin_FILE(), __builtin_LINE() __VA_OPT__(,) ##__VA_ARGS__)
    
    int main()
    {
        tprintf("%d", 1, 2, 3, 4, 5, "dog");
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-05-19
      • 2021-12-27
      • 2011-05-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多