【问题标题】:Why is in-class using-declaration needed when inheriting from lambda types in C++? [duplicate]为什么从 C++ 中的 lambda 类型继承时需要类内使用声明? [复制]
【发布时间】:2021-06-23 08:06:05
【问题描述】:

我想制作一个实用程序,允许将多个 lambda 表达式组合成一个重载的仿函数。在 C++17 中其实很简单,只需要 5 行代码:

template <typename... Funcs>
struct overload : public Funcs... {
    using Funcs::operator()...;
    constexpr overload(Funcs&&... funcs) noexcept : Funcs{funcs}... {}
};

我想知道为什么需要使用声明?最初,当我写这篇文章时,我没有包含 using Funcs::operator()...; 行,编译器 (GCC) 抱怨 operator()() 模棱两可。

为什么这里需要使用声明?据我所知,类内使用声明用于在派生类中生成基类publicprotected 成员。由于 lambda 类型已经将 operator()() 声明为 public,因此 using 声明不应该有所作为。

Here is an example usage code (godbolt):

auto f = overload{
    [](int){return "int ";},
    [](char){return "char ";},
    [](float){return "float ";},
    [](){return "void ";}
};
std::cout << f(3) << f('a') << f();

【问题讨论】:

  • struct A{ void f(int);}; struct B{ void f();}; struct C : A, B {}; C c; c.f(); 也会有歧义。

标签: c++ inheritance lambda overloading using


【解决方案1】:

呼叫接线员有名字。它的名字是operator()。在考虑派生类的接口时,派生的 operator() 名称是名称查找的唯一候选者。

每个基类的operator() 必须导入派生类的命名空间,否则它不是名称查找的候选对象。

和这个是一样的:

struct base
{
  void foo();
};

struct derived : base
{
  // uncomment next line to allow this to compile
  // using base::foo;

  void foo(int);
};

void test(derived& d)
{
    // matches the signature of the base class's foo(), 
    // not the derived classes foo(int)
    d.foo();
}

在上述声明中,derived::foo 是不可用的 base::foo 的影子

【讨论】:

  • 基类成员绝对是名称查找的候选者。否则如何找到它们?您的示例有所不同,因为一旦找到名称,名称查找就会在 derived 中停止。隐藏了其他候选者 - 重载解决方案发生在单个范围内,您的范围是 derived。但在这个问题中,有 4 个深度相同的范围。
  • @MSalters 目前 OP 只有一个答案。如果发布了更好的,我很乐意删除这个。
猜你喜欢
  • 1970-01-01
  • 2018-02-14
  • 2012-08-17
  • 1970-01-01
  • 2018-01-22
  • 2011-04-16
  • 2012-04-05
  • 2011-06-11
  • 1970-01-01
相关资源
最近更新 更多