38

std::visit()cppreference のページ ( https://en.cppreference.com/w/cpp/utility/variant/visit ) を見ると、理解できないコードに遭遇しました...

短縮版は次のとおりです。

#include <iomanip>
#include <iostream>
#include <string>
#include <type_traits>
#include <variant>
#include <vector>

template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...)->overloaded<Ts...>;

int main() {
    std::vector<std::variant<int,long,double,std::string>> vec = { 10, 15l, 1.5, "hello" };
    for (auto& v : vec) {
        std::visit(overloaded{
            [](auto arg) { std::cout << arg << ' '; },
            [](double arg) { std::cout << std::fixed << arg << ' '; },
            [](const std::string& arg) { std::cout << std::quoted(arg) << ' '; },
            }, v);
    }
}

overloadedのすぐ上にある を宣言している 2 行は何int main()を意味していますか?

説明してくれてありがとう!

2019 追加
以下の 2 人の紳士が詳細な説明を提供した後 (どうもありがとうございました!)、非常に優れた本C++17 in Detail - Learn the Exciting Features of The New C++ Standard!で同じコードを偶然見つけました。Bartłomiej Filipekによる。そのようなよく書かれた本!

4

2 に答える 2

21

ああ、私はこれが大好きです。

これは、テンプレート引数の呼び出し演算子のセットにオーバーロードされた呼び出し演算子を使用して構造体を簡潔に宣言する方法です。

template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };

overloadedから継承しTs...、それらのすべてを使用しますoperator()

template<class... Ts> overloaded(Ts...)->overloaded<Ts...>;

これは推定ガイドであるため、テンプレート パラメーターは指定しません。

使い方は例の通りです。

複数のラムダ (およびその他の関数型) のオーバーロードされたセットを作成するのは便利なユーティリティです。


C++17 より前は、再帰を使用して を作成する必要がありましoverloadた。美しくない:

template <class... Fs> struct Overload : Fs...
{
};

template <class Head, class... Tail>
struct Overload<Head, Tail...> : Head, Overload<Tail...>
{
    Overload(Head head, Tail... tail)
        : Head{head}, Overload<Tail...>{tail...}
    {}

    using Head::operator();
    using Overload<Tail...>::operator();
};


template <class F> struct Overload<F> : F
{
    Overload(F f) : F{f} {}

    using F::operator();
};


template <class... Fs> auto make_overload_set(Fs... fs)
{
    return Overload<Fs...>{fs...};
}

auto test()
{
    auto o = make_overload_set(
         [] (int) { return 24; },
         [] (char) { return 11; });

    o(2); // returns 24
    o('a'); // return 11
}

主な煩わしさは、Overload継承が集約ではないため、すべての型でコンストラクターを作成するために再帰のトリックを実行する必要があることです。C++17 ではoverloaded集約 (yey) であるため、構築はそのままで機能します:)。また、それぞれを指定する必要がありusing::operator()ます。

于 2018-09-26T18:19:20.653 に答える