How to use source_location in a variadic template function?

后端 未结 4 902
悲哀的现实
悲哀的现实 2020-12-04 18:07

The C++20 feature std::source_location is used to capture information about the context in which a function is called. When I try to use it with a variadic tem

相关标签:
4条回答
  • 2020-12-04 18:11

    The first form can be made to work, by adding a deduction guide:

    template <typename... Ts>
    struct debug
    {    
        debug(Ts&&... ts, const std::source_location& loc = std::source_location::current());
    };
    
    template <typename... Ts>
    debug(Ts&&...) -> debug<Ts...>;
    

    Test:

    int main()
    {
        debug(5, 'A', 3.14f, "foo");
    }
    

    DEMO

    0 讨论(0)
  • 2020-12-04 18:21

    Just put your arguments in a tuple, no macro needed.

    #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';
    }
    

    And this works*.

    Technically you could just write:

    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';
    }
    

    but then you'd probably have to jump through some hoops to get the argument types.


    * In the linked-to example, I'm using <experimental/source_location> because that's what compilers accept right now. Also, I added some code for printing the argument tuple.

    0 讨论(0)
  • 2020-12-04 18:24
    template <typename... Args>
    void debug(Args&&... args,
               const std::source_location& loc = std::source_location::current());
    

    "works", but requires to specify template arguments as there are non deducible as there are not last:

    debug<int>(42);
    

    Demo

    Possible (not perfect) alternatives include:

    • use overloads with hard coded limit (old possible way to "handle" 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());
      
      // ...
      

      Demo

    • to put source_location at first position, without default:

      template <typename... Args>
      void debug(const std::source_location& loc, Args&&... args);
      

      and

      debug(std::source_location::current(), 42);
      

      Demo

    • similarly to overloads, but just use tuple as group

      template <typename Tuple>
      void debug(Tuple&& t,
                 const std::source_location& loc = std::source_location::current());
      

      or

      template <typename ... Ts>
      void debug(const std::tuple<Ts...>& t,
                 const std::source_location& loc = std::source_location::current());
      

      with usage

      debug(std::make_tuple(42));
      

      Demo

    0 讨论(0)
  • 2020-12-04 18:32

    Not a great solution but... what about place the variadic arguments in a std::tuple?

    I mean... something as

    template <typename... Args>
    void debug (std::tuple<Args...> && t_args,
                std::source_location const & loc = std::source_location::current());
    

    Unfortunately, this way you have to explicitly call std::make_tuple calling it

    debug(std::make_tuple(1, 2l, 3ll));
    
    0 讨论(0)
提交回复
热议问题