C ++ 17 std :: visit示例中令人困惑的模板 [英] Confusing templates in C++17 example of 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屋!