提问人:L. F. 提问时间:8/19/2019 最后编辑:einpoklumL. F. 更新时间:8/31/2022 访问量:5983
如何在可变参数模板函数中使用source_location?
How to use source_location in a variadic template function?
问:
C++20 功能用于捕获有关调用函数的上下文的信息。
当我尝试将它与可变参数模板函数一起使用时,我遇到了一个问题:我看不到放置参数的位置。std::source_location
source_location
以下操作不起作用,因为可变参数必须在末尾:
// doesn't work
template <typename... Args>
void debug(Args&&... args,
const std::source_location& loc = std::source_location::current());
以下方法也不起作用,因为调用方将被中间插入的参数搞砸:
// doesn't work either, because ...
template <typename... Args>
void debug(const std::source_location& loc = std::source_location::current(),
Args&&... args);
// the caller will get confused
debug(42); // error: cannot convert 42 to std::source_location
我在一条评论中被告知可以与可变模板无缝配合,但我很难弄清楚如何。如何使用可变参数模板函数?std::source_location
std::source_location
答:
这不是一个很好的解决方案,但是......将可变参数放在 a 中怎么样?std::tuple
我的意思是。。。作为
template <typename... Args>
void debug (std::tuple<Args...> && t_args,
std::source_location const & loc = std::source_location::current());
不幸的是,这样你必须显式地调用它std::make_tuple
debug(std::make_tuple(1, 2l, 3ll));
评论
std::make_tuple()
只需将您的参数放在元组中,无需宏。
#include <source_location>
#include <tuple>
template <typename... Args>
void debug(
std::tuple<Args...> args,
const std::source_location& loc = std::source_location::current())
{
std::cout
<< "debug() called from source location "
<< loc.file_name() << ":" << loc.line() << '\n';
}
这有效*。
从技术上讲,你可以这样写:
template <typename T>
void debug(
T arg,
const std::source_location& loc = std::source_location::current())
{
std::cout
<< "debug() called from source location "
<< loc.file_name() << ":" << loc.line() << '\n';
}
但是,您可能必须跳过一些障碍才能获得参数类型。
* 在链接的示例中,我使用的是 <experimental/source_location>
,因为这是编译器现在接受的。此外,我还添加了一些用于打印参数元组的代码。
评论
template <typename... Args>
void debug(Args&&... args,
const std::source_location& loc = std::source_location::current());
“works”,但需要指定模板参数,因为没有 last:
debug<int>(42);
可能的(不完美的)替代方案包括:
使用具有硬编码限制的重载(“处理”可变参数的旧方法):
// 0 arguments void debug(const std::source_location& loc = std::source_location::current()); // 1 argument template <typename T0> void debug(T0&& t0, const std::source_location& loc = std::source_location::current()); // 2 arguments template <typename T0, typename T1> void debug(T0&& t0, T1&& t1, const std::source_location& loc = std::source_location::current()); // ...
要放在第一个位置,没有默认值:
source_location
template <typename... Args> void debug(const std::source_location& loc, Args&&... args);
和
debug(std::source_location::current(), 42);
与重载类似,但只需使用元组作为组
template <typename Tuple> void debug(Tuple&& t, const std::source_location& loc = std::source_location::current());
或
template <typename ... Ts> void debug(const std::tuple<Ts...>& t, const std::source_location& loc = std::source_location::current());
用法
debug(std::make_tuple(42));
评论
第一种形式可以通过添加扣除指南来工作:
template <typename... Ts>
struct debug
{
debug(Ts&&... ts, const std::source_location& loc = std::source_location::current());
};
template <typename... Ts>
debug(Ts&&...) -> debug<Ts...>;
测试:
int main()
{
debug(5, 'A', 3.14f, "foo");
}
评论
Ts…
如果函数在 variadiac 参数之前有一个固定参数,例如 printf 格式字符串,则可以将该参数包装在结构中,该结构在其构造函数中捕获source_location:
struct FormatWithLocation {
const char* value;
std::source_location loc;
FormatWithLocation(const char* s,
const std::source_location& l = std::source_location::current())
: value(s), loc(l) {}
};
template <typename... Args>
void debug(FormatWithLocation fmt, Args&&... args) {
printf("%s:%d] ", fmt.loc.file_name(), fmt.loc.line());
printf(fmt.value, args...);
}
int main() { debug("hello %s\n", "world"); }
评论
您可以尝试制作:
#include <iostream>
#include <experimental/source_location>
struct log
{
log(std::experimental::source_location location = std::experimental::source_location::current()) : location { location } {}
template<typename... Args>
void operator() (Args... args)
{
std::cout << location.function_name() << std::endl;
std::cout << location.line() << std::endl;
}
std::experimental::source_location location;
};
int main()
{
log()("asdf");
log()(1);
}
评论
如果你能接受宏的使用,你可以这样写,以避免显式传入:std::source_ location::current()
template <typename... Args>
void debug(const std::source_location& loc, Args&&... args);
#define debug(...) debug(std::source_location::current() __VA_OPT__(,) __VA_ARGS__)
评论
,##
是非标准的,符合要求的替代项是 。__VA_OPT__(,)
评论
debug
std::source_location::current()
std::source_location
auto
42
"foo"