继承函数的重载解决方案

Posted

技术标签:

【中文标题】继承函数的重载解决方案【英文标题】:Overload resolution for inherited functions 【发布时间】:2019-04-09 22:20:21 【问题描述】:

我想要一个结构体,它接受任意数量的 lambda,并作为所有调用运算符的中心调用点。

如果调用运算符的参数列表与构造时给出的任何 lambda 都不匹配,则应调用默认调用运算符。

我认为下面的代码完全可以做到这一点。每个 lambda 的调用运算符都通过 using“提升”到 Poc 类中。

template <typename ...Lambdas>
struct Poc : Lambdas...

    using Lambdas::operator() ...; // Lift the lambda operators into the class

    template <typename ...Ts>
    auto operator() (Ts...)
    
        std::cout << "general call" << std::endl;
    
;

// Deduction guide
template <typename ...Ts>
Poc(Ts... ts)->Poc<Ts...>;

int main()

    auto l_int = [](int) std::cout << "int" << std::endl; ;

    Poc pocl_int;
    poc(1);//calls the default operator. why?

    return 0;

当结构中没有默认调用运算符时,一切都按预期工作(使用有效的参数列表)。如果我将它添加到结构中(如上面的代码中所示),则每次都会调用默认运算符,无论我使用哪个参数调用它。

据我了解,lambda-call-operators 和 structs(默认)call-operator 存在于同一范围内。因此,它们都应该被视为重载解决方案。由于 lamdba-operator 比通用默认操作符更具体,因此应该选择它。

显然情况并非如此。这是为什么呢?

我在Microsoft Visual C++、Clang 和GCC 上进行了测试(全部都是最新版本)。

编辑:

MSVC 15.8.9 GCC 9.0.0(通过Wandbox) Clang 8.0.0(通过Wandbox)

【问题讨论】:

那里有一件很有趣的东西。如果你不介意我会窃取这个想法(只是为了玩得开心;) @YSC 不是CRTP,在CRTP中,derived继承自base&lt;derived&gt; @Walter Ho 这是真的。我让自己被那个代码 sn-p 冲昏了头脑。有趣的是,像我这样的 C++ 书呆子如何用这么少的东西变得欣喜若狂:) 考虑修改:将 all in their latest version 替换为实际版本,以便将来的人们有一个很好的参考点。 @studog 好点,我添加了版本。由于这个概念似乎引起了一些关注,我正在考虑写一篇关于我们实际计划如何使用它的博客文章。 【参考方案1】:

当您发现它时很简单:您的运算符不是const-qualified,而the lambda's one 是(除非您将 lambda 定义为mutable)。因此,它更适合您的非 const 实例 Poc

只需添加缺少的const

auto operator() (Ts...) const

【讨论】:

所以在这种情况下 const 限定胜过模板实例化,它会剔除模板以不生成 *this const? @NathanOliver 是的,这构成了 this 的隐式转换,它将非模板运算符的排名较低。请原谅我,如果我不深入研究超载解决标准,并保持我的“只要平等地限定一切,一切都会好的”的立场;) Just like non-member overload resolution

以上是关于继承函数的重载解决方案的主要内容,如果未能解决你的问题,请参考以下文章

C++ 继承多态关系中的赋值运算符的重载=operator()

C++ 继承多态关系中的赋值运算符的重载=operator()

kotlin用super<>解决类继承接口函数名相同

kotlin用super<>解决类继承接口函数名相同

区分函数重载和函数覆盖

C++继承详解