[英]MSVC: inference of pointer to member function with const and non-const overloads
这是一个最小的示例,其中 MSVC 无法决定是使用成员函数的 const 版本还是非 const 版本:
struct A {
int b() const;
int& b();
};
template <typename T, typename Ref>
void set(A&, Ref (A::*)(), T);
int main() {
auto a = A{};
set(a, &A::b, 123);
}
错误信息是
错误 C2783:“void set(A &,Ref (__cdecl A::*)(void),T)”:无法推断“Ref”的模板参数
GCC 和 Clang 更喜欢非常量方法,并且会毫无问题地编译它。 他们需要Ref (A::*)() const
来选择 const 版本。
有什么方法可以将 MSVC 推向正确的方向吗?
您可以通过强制转换函数指针来强制选择非常量版本:
set(a, static_cast<int & (A::*)()>(&A::b), 123);
我相信这一定是 MSVC 中的错误。 您有一个函数模板的调用,受模板参数推导的约束。 一个参数是指向成员函数类型的指针,因此[temp.deduct.call]/6适用:
当
P
是函数类型、函数指针类型或指向成员函数类型的指针时:
- 如果参数是包含一个或多个函数模板的重载集,则该参数被视为非推导上下文。
- 如果参数是重载集(不包含函数模板),则尝试使用该集的每个成员进行试验参数推导。 如果只有一个重载集成员的推导成功,则该成员将用作推导的参数值。 如果对重载集的多个成员推导成功,则该参数被视为非推导上下文。
在您的例子中,参数是一个不包含任何函数模板的重载集。 因此,通过[temp.deduct.call]/6.2 ,编译器应该尝试对每个方法进行参数推导。 参数推导应该只有一种方法(非常量方法)成功,然后应该是为函数调用选择的方法。
@SoronelHaetir 已经在他的回答中发布了一个解决方法。 我建议您提交错误报告……
另一种方法是切换set
的模板参数,并用decltype
指定第一个:
template <typename Ref, typename T>
void set(A&, Ref (A::*)(), T);
set<decltype(A{}.b())>(a, &A::b, 123);
对于不影响调用者的变通方法,您可以推断类类型并仅在推断类型为 A 时启用该函数。
#include <type_traits>
struct A {
int b() const;
int& b();
};
template <typename T, typename Ref, typename DeducedA,
typename std::enable_if<std::is_same<DeducedA, A>::value, int>::type = 0>
void set(A&, Ref (DeducedA::*)(), T);
int main() {
auto a = A{};
set(a, &A::b, 123);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.