Quel est le problème avec std :: visit en C ++ moderne

Type Sigma et vous


Parlons d'un concept de programmation simple mais puissant - les types sigma.

Un type sigma (somme de type, union étiquetée) peut contenir des valeurs d'un et d'un seul parmi plusieurs types. Par exemple, considérez les paramètres dans un fichier de configuration de type INI . Soit chaque paramètre une chaîne, un entier ou une valeur booléenne. Si nous voulions créer notre bibliothèque en C ++, nous écririons quelque chose comme ceci:

struct Setting {
    union {
        string str;
        int num;
        bool b;
    };
    enum Type { Str, Int, Bool };
    Type tag;
};

//     
using Settings = unordered_map<string, Setting>;

, :

  • tag .
  • .
  • . string, .

, , . getType(), asBool(), asString(), . , , . .

, - . C++17 ! std::variant, .

std::variant


variant — , , . variant<string, int, bool>. variant :

variant<string, int, bool> mySetting = string("Hello!"); // 
mySetting = 42; // 
mySetting = false;

variant, , , . . , :

match (theSetting) {
    Setting::Str(s) =>
        println!("A string: {}", s),
    Setting::Int(n) =>
        println!("An integer: {}", n),
    Setting::Bool(b) =>
        println!("A boolean: {}", b),
};

C++17(*). std::visit. variant, , -, variant.

-? — , :

struct SettingVisitor {
    void operator()(const string& s) const {
        printf("A string: %s\n", s.c_str());
    }

    void operator()(const int n) const {
        printf("An integer: %d\n", n);
    }

    void operator()(const bool b) const {
        printf("A boolean: %d\n", b);
    }
};

, , - . … . -?

make_visitor(
    [&](const string& s) {
        printf("string: %s\n", s.c_str());
        // ...
    },
    [&](const int d) {
        printf("integer: %d\n", d);
        // ...
    },
    [&](const bool b) {
        printf("bool: %d\n", b);
        // ...
    }
)

, make_visitor, . .

template <class... Fs>
struct overload;

template <class F0, class... Frest>
struct overload<F0, Frest...> : F0, overload<Frest...>
{
    overload(F0 f0, Frest... rest) : F0(f0), overload<Frest...>(rest...) {}

    using F0::operator();
    using overload<Frest...>::operator();
};

template <class F0>
struct overload<F0> : F0
{
    overload(F0 f0) : F0(f0) {}

    using F0::operator();
};

template <class... Fs>
auto make_visitor(Fs... fs)
{
    return overload<Fs...>(fs...);
}

, C++11. , F0, , .

, ! C++17 ,

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

, ? , (if constexpr) C++17:

[](auto& arg) {
    using T = std::decay_t<decltype(arg)>;

    if constexpr (std::is_same_v<T, string>) {
        printf("string: %s\n", arg.c_str());
        // ...
    }
    else if constexpr (std::is_same_v<T, int>) {
        printf("integer: %d\n", arg);
        // ...
    }
    else if constexpr (std::is_same_v<T, bool>) {
        printf("bool: %d\n", arg);
        // ...
    }
}

?


std::visit — . : -. , :

  1. , ,
  2. , :
    • ,
    • using- , C++17.


  3. , constexpr if, type_traits, std::decay.

C++-, «» . - , .

?


ISO C++, . , , . , - , . , — - . , … ? ? variant , ? , C++17 , - make_visitor. .

? , . , , SFINAE, - :

template <typename F>
typename std::enable_if<!std::is_reference<F>::value, int>::type
foo(F f)
{
    // ...
}

, std::visit. , , , int string .

, C++ , , . , Effective C++ Effective Modern C++, . , , . , . .

?


, C++ , (*). , . , C++, , C. .

, . D, , . Rust, , unique_ptr shared_ptr ( ), . 2017 , #include.

, , , , , . , . C++ , .

, variant, . - — , . , « , ++».


1. "$\Sigma$-" , . A B, - A B. «» -: -, , .. , A B A B.

2. P0095R1 C++.

3.

Source: https://habr.com/ru/post/fr415737/


All Articles