web-dev-qa-db-ja.com

可変個のテンプレート関数でsource_locationを使用する方法

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を使用するにはどうすればよいですか?

39
L. F.

最初のフォームは、控除ガイドを追加することで機能させることができます。

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");
}

[〜#〜] demo [〜#〜]

35
Piotr Skotnicki

引数をタプルに入れるだけで、マクロは必要ありません。

#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>を使用しています。これは、コンパイラーが現在受け入れているものだからです。また、引数タプルを出力するためのコードを追加しました。

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

「機能する」が、最後がないため推定できないため、テンプレート引数を指定する必要があります。

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));
    

    デモ

4
Jarod42

素晴らしい解決策ではありませんが...可変引数を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));
4
max66