c++ - ¿Cómo usar source_location en una función de plantilla variadic?
variadic-templates c++20 (4)
No es una gran solución, pero ... ¿qué hay de colocar los argumentos variables en una
std::tuple
?
Quiero decir ... algo como
template <typename... Args>
void debug (std::tuple<Args...> && t_args,
std::source_location const & loc = std::source_location::current());
Desafortunadamente, de esta manera tienes que llamar explícitamente a
std::make_tuple
llamándolo
debug(std::make_tuple(1, 2l, 3ll));
La característica C ++ 20
std::source_location
se usa para capturar información sobre el contexto en el que se llama a una función.
Cuando trato de usarlo con una función de plantilla variadic, encontré un problema: no puedo ver un lugar para colocar el parámetro
source_location
.
Lo siguiente no funciona porque los parámetros variables deben estar al final:
// doesn''t work
template <typename... Args>
void debug(Args&&... args,
const std::source_location& loc = std::source_location::current());
Lo siguiente tampoco funciona porque la persona que llama se arruinará por el parámetro insertado en el medio:
// 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
Me informaron en un
comment
que
std::source_location
funciona a la perfección con plantillas variadas, pero me cuesta entender cómo.
¿Cómo puedo usar
std::source_location
source_location con funciones de plantilla variadic?
Simplemente ponga sus argumentos en una tupla, no se necesita macro.
#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'';
}
Y esto works * .
Técnicamente podrías escribir:
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'';
}
pero entonces probablemente tendrías que saltar algunos aros para obtener los tipos de argumento.
* En el ejemplo vinculado, estoy usando
<experimental/source_location>
porque eso es lo que los compiladores aceptan en este momento.
Además, agregué un código para imprimir la tupla de argumento.
template <typename... Args>
void debug(Args&&... args,
const std::source_location& loc = std::source_location::current());
"funciona", pero requiere especificar argumentos de plantilla ya que no son deducibles ya que no son los últimos:
debug<int>(42);
Las posibles alternativas (no perfectas) incluyen:
-
use sobrecargas con límite codificado (antigua forma posible de "manejar" la variadic):
// 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()); // ...
-
para poner
source_location
en la primera posición, sin valor predeterminado:template <typename... Args> void debug(const std::source_location& loc, Args&&... args);
y
debug(std::source_location::current(), 42);
-
de manera similar a las sobrecargas, pero solo use tupla como grupo
template <typename Tuple> void debug(Tuple&& t, const std::source_location& loc = std::source_location::current());
o
template <typename ... Ts> void debug(const std::tuple<Ts...>& t, const std::source_location& loc = std::source_location::current());
con uso
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...>;
Prueba:
int main()
{
debug(5, ''A'', 3.14f, "foo");
}