繁体   English   中英

MSVC:使用 const 和非常量重载推断指向成员函数的指针

[英]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 推向正确的方向吗?

https://godbolt.org/z/ejT-Ls

您可以通过强制转换函数指针来强制选择非常量版本:

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);
}

https://godbolt.org/z/GPxb9xaen

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM