C ++ 17 std :: visit示例中令人困惑的模板 [英] Confusing templates in C++17 example of std::visit

查看:92
本文介绍了C ++ 17 std :: visit示例中令人困惑的模板的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在cppreference中查看 std :: visit()页面时,
https://en.cppreference.com/w/cpp/utility/variant/visit ,我遇到了我无法理解的代码...

When looking at std::visit() page in cppreference, https://en.cppreference.com/w/cpp/utility/variant/visit, I encountered the code I can't make sense of...

以下是缩写版本:

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

这两行声明超载,正好位于 int main()上方,是什么意思?

What do the two lines declaring overloaded, just above int main(), mean?

感谢您的解释!

2019年新增

在以下两位先生提供了详细的解释(非常感谢您!)之后,我在非常精美的 C ++ 17书-
中偶然发现了相同的代码-
了解The的令人兴奋的功能BartłomiejFilipek撰写的新C ++标准!
。这样写得很好!

推荐答案


在int main上方声明超载的两行是什么? (), 意思?

What are the two lines declaring overloaded, just above int main(), mean?

第一个

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

是经典的类/结构声明/定义/实现。从C ++ 11起有效(因为使用可变参数模板)。

is a classic class/struct declaration/definition/implementation. Valid from C++11 (because use variadic templates).

在这种情况下,重载将从所有模板继承参数和启用(使用行)都继承了 operator()。这是 variadic CRTP 的示例。

In this case, overloaded inherits from all template parameters and enables (using row) all inherited operator(). This is an example of Variadic CRTP.

不幸的是,可变的 using 仅从C ++ 17开始可用。

Unfortunately the variadic using is available only starting from C++17.

第二个

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

是推论指南(请参阅​​此页面(了解更多详细信息)),它是C ++ 17的一项新功能。

is a "deduction guide" (see this page for more details) and it's a new C++17 feature.

以您的情况为准,推导指南说,当您将内容写为

In your case, the deduction guide says that when you write something as

auto ov = overloaded{ arg1, arg2, arg3, arg4 };

或者

overloaded ov{ arg1, args, arg3, arg4 };

ov 成为重载了

overloaded
{
    [](auto arg) { std::cout << arg << ' '; },
    [](double arg) { std::cout << std::fixed << arg << ' '; },
    [](const std::string& arg) { std::cout << std::quoted(arg) << ' '; },
}

在C ++ 14中是

auto l1 = [](auto arg) { std::cout << arg << ' '; };
auto l2 = [](double arg) { std::cout << std::fixed << arg << ' '; };
auto l3 = [](const std::string& arg) { std::cout << std::quoted(arg) << ' '; }

overloaded<decltype(l1), decltype(l2), decltype(l3)> ov{l1, l2, l3};

-编辑-

正如Nemo在您的问题示例代码中所指出的(谢谢!),还有一个有趣的C ++ 17新功能:基类的聚合初始化。

As pointed by Nemo (thanks!) in the example code in your question there is another interesting new C++17 feature: the aggregate initialization of base classes.

我的意思是...当您写

I mean... when you write

overloaded
{
    [](auto arg) { std::cout << arg << ' '; },
    [](double arg) { std::cout << std::fixed << arg << ' '; },
    [](const std::string& arg) { std::cout << std::quoted(arg) << ' '; }
 }

您要传递三个lambda函数来初始化<$的三个基类c $ c>重载

you're passing three lambda functions to initialize three base classes of overloaded.

在C ++ 17之前,只有编写了显式构造函数才能执行此操作。从C ++ 17开始,它会自动运行。

Before C++17, you could do this only if you wrote an explicit constructor to do it. Starting from C++17, it works automatically.

这时,在我看来,显示<$ c的简化完整示例可能会很有用。 C ++ 17中$ c> overloaded 和相应的C ++ 14示例。

At this point, it seems to me that it can be useful to show a simplified full example of your overloaded in C++17 and a corresponding C++14 example.

我提出以下C ++ 17程序

I propose the following C++17 program

#include <iostream>

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

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

int main ()
{
    overloaded ov
    {
        [](auto arg) { std::cout << "generic: " << arg << std::endl; },
        [](double arg) { std::cout << "double: " << arg << std::endl; },
        [](long arg) { std::cout << "long: " << arg << std::endl; }
    };
    ov(2.1);
    ov(3l);
    ov("foo");      
 }

和最佳的C ++ 14替代方法(也遵循bolov的建议我可以想象的 make函数和他的递归重载示例)。

and the best C++14 alternative (following also the bolov's suggestion of a "make" function and his recursive overloaded example) that I can imagine.

#include <iostream>

template <typename ...>
struct overloaded;

template <typename T0>
struct overloaded<T0> : public T0
{
    template <typename U0>
    overloaded (U0 && u0) : T0 { std::forward<U0>(u0) }
    { }
};

template <typename T0, typename ... Ts>
struct overloaded<T0, Ts...> : public T0, public overloaded<Ts ...>
{
    using T0::operator();
    using overloaded<Ts...>::operator();

    template <typename U0, typename ... Us>
    overloaded (U0 && u0, Us && ... us)
      : T0{std::forward<U0>(u0)}, overloaded<Ts...> { std::forward<Us>(us)... }
    { }
 };

template <typename ... Ts>
auto makeOverloaded (Ts && ... ts)
{
    return overloaded<Ts...>{std::forward<Ts>(ts)...};
}

int main ()
{
    auto  ov
    {
        makeOverloaded
        (
            [](auto arg) { std::cout << "generic: " << arg << std::endl; },
            [](double arg) { std::cout << "double: " << arg << std::endl; },
            [](long arg) { std::cout << "long: " << arg << std::endl; }
        )
    };
    ov(2.1);
    ov(3l);
    ov("foo");      
 }

我认为这是观点问题,但在我看来C ++ 17版本更简单,更优雅。

I suppose that it's matter of opinion, but it seems to me that the C++17 version is a lot simpler and more elegant.

这篇关于C ++ 17 std :: visit示例中令人困惑的模板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆