c++ - 将重载的 CRTP 类成员方法传递给 lambda

标签 c++ lambda c++17 overloading crtp

考虑一下:

template<typename T>
struct base_t
{
    auto& f(int x) { return (T&)*this; }
    auto& f(char x) { return (T&)*this; }
};

struct derived_t : base_t<derived_t>
{

};

void test()
{
    derived_t instance;

    auto lambda = [&](derived_t&(derived_t::*g)(char))
    {
        (instance.*g)('a');

        //instance.f('a');
    };

    lambda(&derived_t::f);
}
没有在该特定行( //instance.f('a'); )中发表评论,我收到以下错误(MSVC 2019):
error C2664: 'void test::<lambda_1>::operator ()(derived_t &(__cdecl derived_t::* )(char)) const': cannot convert argument 1 from 'overloaded-function' to 'derived_t &(__cdecl derived_t::* )(char)'
当该行没有被注释掉时,它编译得很好。
为什么引用flambda神奇地允许编译器转换这个重载的函数?
此外,如果没有 CRTP,这根本不会发生。
编辑:此外,正如@Jarod42 所指出的,
  • 明确返回类型 auto& -> T& 解决了这个问题。
  • 如果您使用命名函数而不是 lambda,问题就会消失。所以显然 lambda 和模板的交互是相关的。
  • 最佳答案

    模板机制在使用时实例化类和函数。
    使用相同的机制来评估关键字 auto 后面的类型。 .
    在您的情况下,您的 base_t<T>::f 的返回类型功能是 auto& ,并且需要计算一个函数调用。
    因此,当您注释掉对它的唯一调用( instance.f('a'); )时,无法计算该函数的实际签名,并且编译器无法判断它是否可以转换为 derived_t&(derived_t::*g)(char) .
    评论instance.f('a');如果您定义 base_t<T>::f 是可能的功能如下:

    template<typename T>
    struct base_t
    {
        T& f(int) { return *static_cast<T*>(this); }
        T& f(char) { return *static_cast<T*>(this); }
    };
    
    这里的类型是在特殊类型 base_t<derived_t> 的实例化时推导出来的。而不是在 f 的电话中函数,因此编译器可以计算出它到函数类型的转换 derived_t&(derived_t::*g)(char)无需在代码中调用它们。

    关于c++ - 将重载的 CRTP 类成员方法传递给 lambda,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63430081/

    相关文章:

    c++ - 我有某种薛定谔变量

    c++ - 临时对象的 Clang 6 中的模板参数推导被破坏

    c++ - create_directories() 与 create_directories()

    c++ - 无法让我的数组编号与另一组进行比较

    c++ - 在我的函数中使用简单类时出现 undefined reference 错误

    c# - 在 C# 中使用 try catch() 的正确方法

    Java 8 : Map Lambda expression

    c++ - 有没有一种标准方法可以在不使用 Boost 的情况下将 std::string 转换为 std::chrono::time_point?

    c++ - 在 C++ 中制作特定位 "0"

    c# - 从 lambda 表达式方法参数中获取结束值