如何解决将重载的CRTP类成员方法传递给lambda
考虑一下:
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)'
当该行不被注释掉时,它可以很好地编译。
为什么在f
中引用lambda
会神奇地允许编译器转换此重载函数?
此外,没有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)
的转换而无需必须在您的代码中调用它们。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。