MSVC:指向具有const和非const重载的成员函数的指针的推断

时间:2019-04-29 23:03:19

标签: c++ visual-studio visual-c++

这是一个最小的示例,其中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:'无效集(A&,Ref(__cdecl A :: *)(void),T)':无法推断'Ref'的模板参数

GCC和Clang首选non-const方法,并且可以毫无问题地进行编译。他们将需要Ref (A::*)() const来选择const版本。

有什么方法可以将MSVC推向正确的方向?

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

4 个答案:

答案 0 :(得分:3)

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

predictors=df[['Director', 'Length']].copy()

答案 1 :(得分:1)

我相信这一定是MSVC中的错误。您可以调用函数模板,但需要扣除模板参数。一个参数是指向成员函数类型的指针,因此[temp.deduct.call]/6适用于:

  

P是函数类型,函数指针类型或成员函数类型的指针时:

     
      
  • 如果参数是包含一个或多个函数模板的重载集,则该参数将被视为非推论上下文。
  •   
  • 如果参数是一个重载集合(不包含函数模板),则尝试使用该集合的每个成员来推导试验参数。如果仅对重载集合成员之一进行推导成功,则将该成员用作推导的参数值。如果对成功的一组过载成员成功进行推论,则该参数将被视为非推论上下文。
  •   

在您的情况下,该参数是不包含任何函数模板的重载集。因此,通过[temp.deduct.call]/6.2,编译器应尝试使用每个方法进行参数推导。参数推导应仅使用一种方法(非常量方法)才能成功,然后应使用该方法进行函数调用。

@SoronelHaetir已经在他的答案中发布了一种解决方法。我建议你file a bugreport

答案 2 :(得分:0)

完成此工作的另一种方法是切换set的模板参数,并用decltype指定第一个:

template <typename Ref, typename T>
void set(A&, Ref (A::*)(), T);

set<decltype(A{}.b())>(a, &A::b, 123);

答案 3 :(得分:0)

对于不影响调用者的解决方法,您可以推断出类类型,并且仅在推断出的类型为 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