C++:使用声明和重载范例

C++: using declaration and overload paradigm

我正在查看 this page 关于 C++17 的“新”特性。 特别是我几乎理解以下所有代码:

#include <iostream>
#include <variant>

struct Fluid { };
struct LightItem { };
struct HeavyItem { };
struct FragileItem { };

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

int main() {
    std::variant<Fluid, LightItem, HeavyItem, FragileItem> package;

    std::visit(overload{
        [](Fluid& )       { std::cout << "fluid\n"; },
        [](LightItem& )   { std::cout << "light item\n"; },
        [](HeavyItem& )   { std::cout << "heavy item\n"; },
        [](FragileItem& ) { std::cout << "fragile\n"; }
    }, package);
}

我做的不是理解的是

using Ts::operator()...;

在结构 overload 的定义中。据我所知,这样使用 using 关键字是为了确保 operator() 成为 public。但就涉及 lambda 而言,在我看来已经 public。所以我会说这是多余的。我尝试用

编译和执行
template<class... Ts> struct overload : Ts... { };

一切正常。我错了吗?我错过了什么吗?

using 目的不仅是为了改变可访问性,而且是为了“解决”歧义 and/or 取消隐藏基本方法。

https://en.cppreference.com/w/cpp/language/unqualified_lookup#Member_function_definition

otherwise, if the declaration sets in Bi and in C are different, the result is an ambiguous merge: the new lookup set of C has an invalid declaration and a union of the subobjects ealier merged into C and introduced from Bi. This invalid lookup set may not be an error if it is discarded later.

struct Base1
{
    void foo() {}
};

struct Base2
{
    void foo(int) {}
};

struct D : Base1, Base2
{
    // using Base1::foo; // Those would solve the ambiguity
    // using Base2::foo;

    void bar()
    {
        foo(); // ambiguous
    }
}

struct D2 : Base1
{
    // using Base1::foo; // This would unhide Base1::foo

    void foo(char) {} // hides Base1::foo

    void bar()
    {
        foo(); // wrong, find D2::foo(char)
    }
}

using Ts::operator()...; 就是可变参数语法。