繁体   English   中英

指向派生类成员的 C++ 指针

[英]C++ pointer to member of derived class

我不明白这里发生了什么。 我有一个包含字段a的类Base 现在我创建了一个扩展 Base 的Derived类。 我还有一个模板函数,它通过传递指向成员的模板参数来打印我们想要的字段。

#include <iostream>

class Base {
public:
  Base(double a):a{a} {}
  double a;
};

class Derived : public Base {
public:
  Derived(double a) : Base(a) {}
};

template<double (Derived::*p)>
void print(Derived d) {
  std::cout << d.*p;
}

int main() {
  Derived d {10.0};
  print<&Derived::a>(d);
}

问题是它不起作用,但如果我只使用基类:

template<double (Base::*p)>
void print(Base b) {
  std::cout << b.*p;
}

int main() {
  Base b {10.0};
  print<&Base::a>(b);
}

它按预期工作并打印10.0 我怎样才能让它与子类一起工作?

编译器说:

test.cpp:15:6: note:   template argument deduction/substitution failed:
test.cpp:21:23: error: could not convert template argument ‘&Base::a’ from ‘double Base::*’ to ‘double Derived::*’
   print<&Derived::a>(d);

正如其他人解释的原因,我将解释解决方案:

template<typename T, double (T::*p)>
void print(T d) {
  std::cout << d.*p;
}


int main() {
  Derived d {10.0};
  print<Base, &Base::a>(d);
}

https://gcc.godbolt.org/z/pM762f

我敢肯定这不是您所希望的,但总比重载每个版本要好。 但我认为最好找到解决问题的更好方法,因为我知道这里的代码不是您实际面临的问题,因为您可以传递 double 本身而不是成员指针。

因此,请尝试在您的代码上下文中解决问题,而不是通过这种方式。 以下是一些可能会解决您实际问题的想法(如果您有的话):

  • 使用enum
  • 想一下std::map如果不是太多
  • 您可以使用 lambda(它们现在是constexpr ,因此您也可以在模板中使用它们)
  • 考虑将print功能移到基类甚至派生类中
  • 使用高阶函数(太多 lambda 本质上:D)而不是整个面向对象的解决方案。

以及许多其他解决方案,其中大多数可能对您没有帮助(因为我不知道您的代码的上下文)。

这将是仅编译器消息就具有人们必须想要的所有解释的示例之一:

<source>: In function 'int main()':

<source>:21:23: error: no matching function for call to 'print<&Base::a>(Derived&)'
   21 |   print<&Derived::a>(d);
      |                       ^
<source>:15:6: note: candidate: 'template<double Derived::* p> void print(Derived)'
   15 | void print(Derived d) {
      |      ^~~~~
<source>:15:6: note:   template argument deduction/substitution failed:
<source>:21:23: error: '&Base::a' is not a valid template argument for type 'double Derived::*'

   21 |   print<&Derived::a>(d);
      |                       ^
<source>:21:23: note: because it is a member of 'Base'
Compiler returned: 1

回答评论中的一个问题:模板参数不能隐式转换为指向 base 成员的指针,而static_cast也无济于事,因为对于作为成员指针的模板非类型参数,必须以&C::m的形式编写(请参阅https://en.cppreference.com/w/cpp/language/pointer#Pointers_to_members

不是那么明显,但是指向a的成员指针的类型是double Base::* ,无论它指向Derived对象还是Base对象中的a 您的方法只接受一个Derived参数,并且只接受一个指向Derived中的成员的指针作为模板参数。 如果你想允许不同的组合,你可以写更多的重载。

暂无
暂无

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

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