[英]Distinguish between function references/pointers accepting const and non-const argument with same name as function parameter
让我们考虑两个具有相同名称的函数:
int func(int&)
{
return 7;
}
int func(const int&)
{
return 5;
}
让int mutableValue = 5
在某处定义。 call(mutableValue, func)
中的模板函数call
是否有可能只需要int func(int&)
? 我不想使用static_cast<int(&)(int&)>
- 因为它太吵了。
幼稚的实现:
template<typename Arg, typename Ret>
void call(Arg& val, Ret (&fun)(Arg&))
{
fun(val);
}
适用于 gcc,但不适用于 clang - 解决方案必须适用于两个编译器。
只接受const Arg&
很容易。 删除const Arg&
重载无济于事。
我相信 clang 是唯一能做到这一点的编译器。 这不应该编译。 只要fun
的参数是不包含任何函数模板的重载集,就会为重载集的每个成员尝试模板参数推导。 如果模板参数推导对这些重载中的一个以上成功,则函数参数将成为非推导上下文[temp.deduct.call]/6.2 。
在所讨论的示例中, fun
的参数是重载集func
,它确实不包含任何函数模板。 因此,对func
两个重载都尝试对fun
参数推导,结果成功。 结果,参数fun
变成了一个非推导的上下文,这意味着不能为Ret
推导任何参数,并且调用失败,因为没有候选对象(正是 clang 抱怨的)。
要消除此调用的歧义,只需明确指定第一个模板参数的参数:
call<int>(mutableValue, func)
由于在一个模板参数推导中解决歧义似乎是不可能的:
如果您对调用站点的语法更改没有意见,您可以将调用分为两个调用/推导传递:
template<typename Arg>
auto call(Arg& val)
{
return [&](auto (&fun)(Arg&)){ fun(val); };
}
被称为
call(mutableValue)(func)
然而,另一个缺点是 lambda 可能由调用者存储,并在捕获的引用不再有效时意外使用。
您可以将其隐藏在宏调用中,以便语法与您想要的匹配并减少误用的可能性。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.