作者:建霖怡旭家其 | 来源:互联网 | 2022-12-03 18:10
std::visit()
在cppreference中查看页面时,https: //en.cppreference.com/w/cpp/utility/variant/visit,
我遇到了我无法理解的代码......
这是缩写版本:
#include
#include
#include
#include
#include
#include
template struct overloaded : Ts... { using Ts::operator()...; };
template overloaded(Ts...)->overloaded;
int main() {
std::vector> vec = { 10, 15l, 1.5, "hello" };
for (auto& v : vec) {
std::visit(overloaded{
[](auto arg) { std::cout <
这两条线overloaded
在上面宣布int main()
是什么意思?
谢谢你的解释!
1> max66..:
声明重载的两行是什么,就在int main()之上,是什么意思?
第一个
template
struct overloaded : Ts...
{ using Ts::operator()...; };
是经典的类/结构声明/定义/实现.从C++ 11开始有效(因为使用可变参数模板).
在这种情况下,overloaded
继承所有模板参数并启用(using
行)所有继承的operator()
.这是Variadic CRTP的一个例子.
不幸的是,变量using
只能从C++ 17开始提供.
第二个
template overloaded(Ts...) -> overloaded;
是一个"演绎指南"(有关详细信息,请参阅此页面),这是一个新的C++ 17功能.
在您的情况下,扣除指南说当你写一些东西时
auto ov = overloaded{ arg1, arg2, arg3, arg4 };
或者也
overloaded ov{ arg1, args, arg3, arg4 };
ov
成为一个 overloaded
这允许你写一些东西
overloaded
{
[](auto arg) { std::cout <
在C++ 14中是
auto l1 = [](auto arg) { std::cout < ov{l1, l2, l3};
- 编辑 -
正如Nemo(谢谢!)在您的问题的示例代码中所指出的,还有另一个有趣的新C++ 17特性:基类的聚合初始化.
我的意思是......当你写作时
overloaded
{
[](auto arg) { std::cout <
你正在传递三个lambda函数来初始化三个基类overloaded
.
在C++ 17之前,只有在编写显式构造函数的情况下才能执行此操作.从C++ 17开始,它会自动运行.
在这一点上,在我看来,overloaded
在C++ 17和相应的C++ 14示例中显示简化的完整示例非常有用.
我提出以下C++ 17程序
#include
template
struct overloaded : public Ts ...
{ using Ts::operator()...; };
template overloaded(Ts...) -> overloaded;
int main ()
{
overloaded ov
{
[](auto arg) { std::cout <<"generic: " <
和我最好的C++ 14替代方案(以及overloaded
我可以想象的bolov建议的"make"函数和他的递归示例).
#include
template
struct overloaded;
template
struct overloaded : public T0
{
template
overloaded (U0 && u0) : T0 { std::forward(u0) }
{ }
};
template
struct overloaded : public T0, public overloaded
{
using T0::operator();
using overloaded::operator();
template
overloaded (U0 && u0, Us && ... us)
: T0{std::forward(u0)}, overloaded { std::forward(us)... }
{ }
};
template
auto makeOverloaded (Ts && ... ts)
{
return overloaded{std::forward(ts)...};
}
int main ()
{
auto ov
{
makeOverloaded
(
[](auto arg) { std::cout <<"generic: " <
我认为这是意见问题,但在我看来,C++ 17版本更简单,更优雅.
2> bolov..:
啊,我喜欢这个.
这是一种简单地声明一个结构,其中一个调用操作符在模板参数调用操作符的集合上重载.
template struct overloaded : Ts... { using Ts::operator()...; };
overloaded
继承Ts...
并使用他们所有的operator()
template overloaded(Ts...)->overloaded;
这是一个演绎指南,因此您不需要指定模板参数
用法如您在示例中所示.
这是一个很好的实用程序来创建一组多个lambda(和其他函数类型)的重载.
在C++ 17之前,您必须使用递归来创建overload
.不漂亮:
template struct Overload : Fs...
{
};
template
struct Overload : Head, Overload
{
Overload(Head head, Tail... tail)
: Head{head}, Overload{tail...}
{}
using Head::operator();
using Overload::operator();
};
template struct Overload : F
{
Overload(F f) : F{f} {}
using F::operator();
};
template auto make_overload_set(Fs... fs)
{
return Overload{fs...};
}
auto test()
{
auto o = make_overload_set(
[] (int) { return 24; },
[] (char) { return 11; });
o(2); // returns 24
o('a'); // return 11
}
主要的麻烦是Overload
因为inherits不是聚合,所以你需要做递归技巧来创建一个包含所有类型的构造函数.在C++中,17 overloaded
是一个聚合(yey),因此构建一个开箱即用的工具:).您还需要using::operator()
为每个指定.