【问题标题】:Overloading structs with template call operator and generic lambdas - gcc vs clang使用模板调用运算符和通用 lambda 重载结构 - gcc vs clang
【发布时间】:2017-05-15 15:02:51
【问题描述】:

我发现了一个代码 sn-p 可以在 clang++ 4(和 trunk) 中正常编译和工作,但在 g++ 7(和 trunk) 中无法编译。假设我有以下struct 类型:

struct a { void foo() { } };
struct b { void bar() { } };
struct c { void bar() { } };

我想用 lambdas 创建一个 重载集,它显式处理 a,而 bc 使用 auto 参数被通用 lambda “捕获”:

auto ol = overload([](a x)   { x.foo(); },
                   [](auto x){ x.bar(); })

当我调用ol(a{}):

  • clang++ 编译并按预期运行:a“匹配”第一个 lambda,而 bc 匹配第二个。

  • g++编译失败,报错如下:

    error: 'struct a' has no member named 'bar'
               [](auto x){ x.bar(); };
                           ~~^~~
    

    编译器似乎试图实例化第二个 lambda,即使第一个是更好的匹配方式。希望这是一个错误,因为这对我来说似乎不直观。


请注意,如果我使用一些老式的 struct 实例而不是 lambda 表达式,则两个编译器都能正常工作:

struct s0
{
    auto operator()(a x) const { x.foo(); }
};

struct s1
{
    template <typename T>
    auto operator()(T x) const { x.bar(); }
};

auto os = overload(s0{}, s1{});
os(a{}); // OK!

我希望 lambda 大致相当于 s0s1,所以这更令人惊讶。


这是我产生重载集的方式:

template <typename... Fs>
struct overloader : Fs...
{
    template <typename... FFwds>
    overloader(FFwds&&... fs) : Fs{std::forward<FFwds>(fs)}...
    {
    }

    using Fs::operator()...;
};

template <typename... Fs>
auto overload(Fs&&... fs)
{
    return overloader<std::decay_t<Fs>...>{std::forward<Fs>(fs)...};
}

这是一个live example on gcc.godbolt.org,显示了编译器之间的不同行为。


这是一个 g++ 错误吗? 还是标准中的某些东西使 lambda 在这种情况下的行为与 struct 实例不同?

【问题讨论】:

  • 咦,using &lt;&gt; ...什么时候进标准了? C++17?
  • @NirFriedman 是的,在 C++17 中,感谢P0195
  • 旁白:能够将函数指针作为overload 的参数很好。为此,请将: Fs... 替换为: some_magic&lt;Fs&gt;...,其中some_magic 检测函数指针并将其映射到存储它的类,以及它留下的所有其他内容。 (但也许这个重载是一个简化的 MCVE,在这种情况下忽略它)

标签: c++ lambda overloading language-lawyer c++17


【解决方案1】:

我认为这是一个 gcc 错误(以80767 提交),与[temp.inst]/9 发生冲突:

实现不应隐式实例化函数模板、变量模板、成员模板、非虚拟成员函数、成员类、类模板的静态数据成员或 constexpr if 语句的子语句,除非需要这样的实例化。

不需要用auto = a 实例化通用lambda 的operator(),因此不应实例化它。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2021-06-20
  • 2015-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-03
  • 2023-03-16
相关资源
最近更新 更多