使用作为模板形参提供的基类成员,不带限定符

Use members of a base class provided as a template parameter without qualifiers

本文关键字:成员 基类 形参      更新时间:2023-10-16

代码正常运行:

struct Defs
{
    static const int a = 1;
    int b{};
    void g() {}
};
struct Bob : Defs
{
    void f()
    {
        cout << a << "n";
        cout << b << "n";
        g();
    }
};
int main()
{
    Bob b;
    b.f();
}

但是这段代码没有:

struct Defs
{
    static const int a = 1;
    int b{};
    void g() {}
};
template<class D>
struct Bob : D
{
    void f()
    {
        cout << a << "n";
        cout << b << "n";
        g();
    }
};
int main()
{
    Bob<Defs> b;
    b.f();
}

错误:

prog.cpp: In member function 'void Bob<D>::f()':
prog.cpp:16:11: error: 'a' was not declared in this scope
   cout << a << "n";
           ^
prog.cpp:17:11: error: 'b' was not declared in this scope
   cout << b << "n";
           ^
prog.cpp:18:5: error: there are no arguments to 'g' that depend on a template parameter, so a declaration of 'g' must be available [-fpermissive]
   g();
     ^
prog.cpp:18:5: note: (if you use '-fpermissive', G++ will accept your code, but allowing the use of an undeclared name is deprecated)

但是如果我做以下操作,它就可以工作了:

template<class D>
struct Bob : D
{
    void f()
    {
        cout << D::a << "n";
        cout << D::b << "n";
        D::g();
    }
};

是否有可能让一个类使用作为模板形参提供的基类的成员,而不限定它们?我问这个问题的原因是,这样做可以让我重构一些代码,而不需要做很多改变。

可以假设用作模板形参的类型具有所有这些成员,否则可以接受编译失败。

简介

出现错误是因为基类依赖于模板参数,这并不奇怪,因为基类直接使用模板参数

错误诊断来自于这样一个事实:不同的模板参数可能在类内部产生明显不同的行为;如果传入的模板参数没有特定的成员怎么办?然后我们要在全局范围内查找一些东西吗?

  • 在哪里,为什么我必须把"模板"answers"typename"关键字?

显式声明想要访问this的成员

你是说你想访问基类的成员而不限定它们,如果我从字面上理解你的话,我会说你可以使用this->member-name —但考虑到你写的关于重构的内容,我怀疑这是不是你想要的。

struct A { 
  int m;
};
template<class T>
struct B : T { 
  void func () {
    this->m = 1;
  }
};
int main () {
  B<A> {}.func (); 
}

依赖的基类

引入名称

另一种选择是显式声明您希望基类中的某些名称在派生它的基类中直接可用—使用using,如下所示:

template<class T>
struct B : T {
  using T::m;
  void func () {
    m = 1;
  }
};

可以读作;"亲爱的编译器,无论我指的是m,我希望你使用T中的一个"


但是我想破解这个问题;怎样! ?

引入一个非依赖基并让它引入引用到你真正想要的数据。如果您知道每个T的名称,那么这将有效。

你甚至可以扩展这个hack,让它自动推断出那些成员的类型,但这与问题的范围相去甚远。

#include <iostream>
struct A {
  int n;
  int m;
  void print () {
    std::cout << m << std::endl;
  }
};
struct Hack {
  template<class T>
  Hack (T* hck) : m (hck->m), n (hck->n) { }
  int& m;
  int& n;
};
template<class T>
struct B : T, Hack {
  B () : Hack (static_cast<T*> (this)) { }
  void func () {
    m = 123;
  }
};
int main () {
  B<A> b;
  b.func ();
  b.print ();
}

你可以在这里找到一个运行的例子。警告的话;我个人是不会这么做的,但正如你所看到的,你可以通过一些间接的方式来完成你的要求。

您可以添加:

using D::a;
using D::b;
using D::g;

Bob修复你的作用域问题。

下面是对这个问题的全面概述。老实说,这是c++中不应该存在的一个角落,但是,没有语言是完美的=P