首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在派生类初始值设定项列表中初始化模板基类成员类型

在派生类初始值设定项列表中初始化模板基类成员类型
EN

Stack Overflow用户
提问于 2009-07-13 04:24:37
回答 3查看 31.9K关注 0票数 15

下面是一些代码,概述了我一直在努力解决的一个问题。最后一个问题(就目前的g++而言)是:“错误:'Foo-T‘没有在这个作用域中声明”,当执行Bar::Bar(...)构造函数例程。否则,我要学习的问题之一就是如何根据使用模板传递给派生类构造函数的参数来设置基类成员类型。如果有一种方法可以简单地通过将参数传递给派生类构造函数来设置基类成员类型(T Foo-T),我更希望这样做。到目前为止,我还看不到使用模板参数和匹配的派生类构造函数参数来完成此任务的方法。你能在下面的代码中找出我可以做得更好的地方来实现同样的目标吗?我对泛型编码和模板比较陌生。

代码语言:javascript
复制
#include <iostream>
typedef int a_arg_t;
typedef double b_arg_t;
typedef std::string foo_arg_t;

class TypeA {
public:
    TypeA ();
    TypeA (a_arg_t a) {
      /* Do sosmething with the parameter passed in */
    }

};

class TypeB {
public:
    TypeB ();
    TypeB (b_arg_t b) {
      /* typeB's constructor - do something here */
    }

};

// The base-class with a member-type to be determined by the template argument
template <class T>
class Foo {

public:
    Foo (const foo_arg_t foo_arg) : _foo_arg(foo_arg) // initialize something here
    {
      /* do something for foo */
    }
    T Foo_T; // either a TypeA or a TypeB - TBD
    foo_arg_t _foo_arg;
};

// the derived class that should set the basse-member type (T Foo_T)
template <class T>
class Bar : public Foo<T> {
public:
    Bar (const foo_arg_t bar_arg, const a_arg_t a_arg)
    : Foo<T>(bar_arg) // base-class initializer
    {
        // the initialization of Foo_T has to be done outside the initializer list because it's not in scsope until here
        Foo_T = TypeA(a_arg); // if an a_arg_t is passed in, then we set the Foo_T to TypeA, etc.
    }

    Bar (const foo_arg_t bar_arg, const b_arg_t b_arg)
    : Foo<T>(bar_arg)
    {
        Foo_T = TypeB(b_arg);
    }

};

int main () {

    b_arg_t b_arg;
    a_arg_t a_arg;
    foo_arg_t bar_arg;

    Bar<TypeA> a (bar_arg, a_arg); // try creating the derived class using TypeA
    Bar<TypeB> b (bar_arg, b_arg); // and another type for show

return 0;
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2009-07-13 09:20:50

当在派生(栏)构造函数中使用时,将不会在基类中查找Foo_T类型。

代码语言:javascript
复制
Bar (const foo_arg_t bar_arg, const a_arg_t a_arg)
: Foo<T>(bar_arg)   // base-class initializer
{
    Foo_T = TypeA(a_arg);   TypeA, etc. // Won't compile, per the standard
}

这是根据C++标准进行的,该标准规定非限定名通常是非依赖的,应该在完全定义模板时进行查找。

由于模板基类定义当时是未知的(可能会有模板的完全专门化实例稍后在编译单元中被拉入),所以不合格的名称永远不会被解析为依赖基类中的名称。

如果涉及模板时需要基类中的名称,则必须完全限定它们,或者使它们隐式依赖于派生类。

代码语言:javascript
复制
 Foo< T >::Foo_T = TypeA(a_arg);   // fully qualified will compile

或者,使其依赖于

代码语言:javascript
复制
 this->Foo_T = TypeA(a_arg);

因为this使其依赖于模板,所以解析类型被推迟到模板实例化的“阶段2”(然后,基类也是完全已知的)

请注意,如果要使用基类中的函数,还可以添加using声明。

(栏内())

代码语言:javascript
复制
  some_foo_func(); // wouldn't work either

  using Foo<T>::some_foo_func;
  some_foo_func(); // would work however
票数 20
EN

Stack Overflow用户

发布于 2009-07-13 04:37:13

很抱歉帮不上忙,但如果不按照你说的做,我也看不到解决这个问题的办法:

到目前为止,我还看不到使用模板参数和匹配的派生类构造函数参数来完成此任务的方法。

你可能需要专门化一下:

代码语言:javascript
复制
template<>
Bar<TypeA>::Bar (const foo_arg_t bar_arg, const a_arg_t a_arg)
: Foo<TypeA>(bar_arg)   // base-class initializer
{
    // the initialization of Foo_T has to be done outside the initializer list because it's not in scsope until here
    Foo_T = TypeA(a_arg);   // if an a_arg_t is passed in, then we set the Foo_T to TypeA, etc.
}

template< class T>
Bar<T>::Bar (const foo_arg_t bar_arg, const a_arg_t a_arg)
: Foo<T>(bar_arg)   // base-class initializer
{
    // Throw exception?
}

template<>
Bar<TypeB>::Bar (const foo_arg_t bar_arg, const b_arg_t b_arg)
: Foo<TypeB>(bar_arg)
{
    Foo_T = TypeB(b_arg);
}

template< class T >
Bar<T>::Bar (const foo_arg_t bar_arg, const b_arg_t b_arg)
: Foo<T>(bar_arg)
{
    // Throw exception ?
}

不幸的是,我现在无法访问编译器来检查这段代码,所以要小心。

回答你的问题/评论。我需要编译以下代码:

代码语言:javascript
复制
#include <iostream>
typedef int a_arg_t;
typedef double b_arg_t;
typedef std::string foo_arg_t;

class TypeA {
public:
  TypeA () {}
  TypeA (a_arg_t a) {}
};

class TypeB {
public:
  TypeB () {}
  TypeB (b_arg_t b) {}
};

template <class T>
class Foo {
public:
  Foo (const foo_arg_t foo_arg) : _foo_arg(foo_arg) {}
  T Foo_T;        // either a TypeA or a TypeB - TBD
  foo_arg_t _foo_arg;
};

// the derived class that should set the basse-member type (T Foo_T)
template <class T>
class Bar : public Foo<T> {
public:
  Bar (const foo_arg_t bar_arg, const a_arg_t a_arg)
  : Foo<T>(bar_arg)   // base-class initializer
  {
    Foo<T>::Foo_T = TypeA(a_arg);
  }

  Bar (const foo_arg_t bar_arg, const b_arg_t b_arg)
  : Foo<T>(bar_arg)
  {
    Foo<T>::Foo_T = TypeB(b_arg);
  }
};

int main () {
  b_arg_t b_arg;
  a_arg_t a_arg;
  foo_arg_t bar_arg;

  Bar<TypeA> a (bar_arg, a_arg);  // try creating the derived class using TypeA
  Bar<TypeB> b (bar_arg, b_arg); // and another type for show

  return 0;
}
票数 3
EN

Stack Overflow用户

发布于 2009-07-13 06:55:37

当我第一次看你的代码时,我绝对确定你必须用部分专门化来解决这个问题。事实上,这种情况可能仍然存在,但是,我已经减少了复制您的错误所需的代码量,并观察到错误只发生在使用gcc编译时(我不知道我的大学运行的是哪个编译器版本),以及使用Visual Studio2003编译时-一切都很顺利。

以下代码复制了错误代码,但一个看似无害的微小更改将出人意料地消除它:

代码语言:javascript
复制
template <typename T>
class ClassA
{
public:
    ClassA () {}
    T vA;
};


template<typename T>
class ClassB : public ClassA<T>
{
public:
    ClassB ()
    {
        vA = 6;
    }
};

int main ()
{
    ClassB<int> cb;
}

现在,如果您从ClassB中删除模板声明,并让它直接从ClassA继承:

代码语言:javascript
复制
class ClassB : public ClassA<int>
{
public:
    ClassB ()
    {
        vA = 6;
    }
};

然后更改cb的声明以匹配

代码语言:javascript
复制
    ClassB cb;

然后,错误就消失了,即使关于vA (或者在您的例子中是Foo_T)的作用域没有什么不同

我推测这是一个编译器错误,我想知道是否一个完全最新的gcc编译器仍然会遇到这个问题。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1117693

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档