使用模板调用运算符和通用Lambda重载结构-GCC与Clang [英] Overloading structs with template call operator and generic lambdas - gcc vs clang

查看:98
本文介绍了使用模板调用运算符和通用Lambda重载结构-GCC与Clang的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我发现了一个代码片段,可以在 clang ++ 4(和主干)中编译并正常工作,但是无法在 g ++ 7(和主干)中进行编译.假设我具有以下struct类型:

I have discovered a code snippet that compiles and works properly in clang++ 4 (and trunk) but fails to compile in g++ 7 (and trunk). Let's assume I have the following struct types:

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

我想从显式处理a的lambda中创建一个过载集,而bc被使用auto参数的通用lambda捕获":

I want to create an overload set out of lambdas which handles a explicitly, while b and c are "caught" with a generic lambda using an auto parameter:

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

当我调用ol(a{})时:

  • clang ++ 编译并按预期方式运行:a匹配"第一个lambda,而bc匹配第二个lambda.

  • clang++ compiles and behaves as expected: a "matches" the first lambda, while b and c match the second one.

g ++ 编译失败,出现以下错误:

g++ fails to compile, with the following error:

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

似乎编译器尝试实例化第二个lambda,即使第一个lambda可以更好地匹配.希望这是一个错误,对我来说似乎不直观.

It seems that the compiler tries to instantiate the second lambda even though the first one is a way better match. Hopefully this is a bug, as it seems unintuitive to me.

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

Note both compilers work properly if instead of lambda expressions I use some old-fashioned struct instances:

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,所以这更加令人惊讶.

I would expect the lambdas to be roughly equivalent to s0 and s1, so this is even more surprising.

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

This is the way I'm producing the overload set:

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)...};
}

这是gcc.godbolt.org 上的 实时示例,显示了不同的地方编译器之间的行为.

And here's a live example on gcc.godbolt.org, showing the different behavior between the compilers.

这是g ++错误吗?或者在这种情况下,标准中是否存在某些使lambda行为不同于struct实例的行为?

Is this a g++ bug? Or is there something in the standard that makes lambdas behave differently from struct instances in this situation?

推荐答案

我认为这是gcc错误(提交为:

I think this is a gcc bug (submitted as 80767), running afoul of [temp.inst]/9:

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

An implementation shall not implicitly instantiate a function template, a variable template, a member template, a non-virtual member function, a member class, a static data member of a class template, or a substatement of a constexpr if statement, unless such instantiation is required.

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

The instantiation of the generic lambda's operator() with auto = a is not required, hence it should not be instantiated.

这篇关于使用模板调用运算符和通用Lambda重载结构-GCC与Clang的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆