在不同的命名空间中调用别名声明的基类构造函数



我试图通过c++ 11的using理解别名声明类的一些细节,以及它如何/为什么影响基类构造函数调用。

示例代码

#include <iostream>
namespace N {
  template<typename T>
  struct Foo
  {
//     Foo(){}; // NOTE: If this line is present, error 2 goes away.
    Foo(T t):value(t){};
    ~Foo() = default;
    T value; 
  };
  struct BarInt : public Foo<int>
  {
    BarInt(int t):Foo< int >(t){};
    ~BarInt() = default;
  };
  using BarFloat = Foo<float>;
};
struct A : public N::BarInt
{
  A(int i=42):BarInt(i){}; //BarInt(i) or N::BarInt(i) doesn't matter here
  ~A() = default;
};
struct B : public N::BarFloat
{
  B(float f=23.0):BarFloat(f){}; //two errors with gcc4.7.2 (with -std=gnu++11)
//   B(float f=23.1):N::BarFloat(f){}; //this line seems to work.
  ~B() = default;
};

int main(int argc, char **argv)
{
  A a;
  B b;  
  std::cout << "a's value is "<< a.value << "n"
            << "b's value is "<< b.value << std::endl;
  return 0;
}

gcc 4.7.2(使用-std=gnu++11编译)为这段代码生成两个错误,我认为这是相关的(尽管我不明白如何…)

错误1

main.cpp: In constructor ‘B::B(float)’:
main.cpp:32:19: error: class ‘B’ does not have any field named ‘BarFloat’
在引用基类时需要一个命名空间,它提到注入的类名作为进一步搜索的起点。然而,从我收集到的,这解释了为什么我可以像我那样为A编写构造函数(即作为A(int i=42):BarInt(i){};),以及为什么BarInt(i)不必使用名称空间N进行限定。

那么为什么B不起作用呢?根据'typedef'和& # 39;使用# 39;在c++中11吗?, using是一样的一个很好的旧typedef,所以我想我的第一个错误的问题是如何别名声明类(BarFloat在我的例子)不同于常规类(BarInt在我的例子)在注入类名的上下文中。任何提示都非常感谢:)

错误2

main.cpp:32:29: error: no matching function for call to ‘N::Foo<double>::Foo()’
main.cpp:32:29: note: candidates are:
main.cpp:9:5: note: N::Foo<T>::Foo(T) [with T = double]
main.cpp:9:5: note:   candidate expects 1 argument, 0 provided
main.cpp:6:10: note: constexpr N::Foo<double>::Foo(const N::Foo<double>&)
main.cpp:6:10: note:   candidate expects 1 argument, 0 provided

如果像上面的示例代码中已经指出的那样,引入一个空的Foo()构造函数,则此错误将消失。然而,我的问题是,为什么BarFloat(f)触发对空Foo()构造函数的调用,在这种情况下,BarFloat.value如何可能被设置为23.0。

后记

因为这是我在这里的第一个帖子:你好stackoverflow,感谢你所有的巨大的帮助,你已经提供给我通过帮助别人解决他们的问题!

当您从一个类继承时,派生类可以无限制地访问基类的名称(包括基类名称本身)。您实际上继承了基类中的名称。这就是为什么从N::BarInt继承允许您在A中不加限定地引用BarInt

对于B,您使用BarFloat别名从Foo<double>继承,但Foo<double>不包含BarFloat,因此您不继承该名称。

第二个错误仅仅是因为第一个失败。由于编译器没有看到基类的有效初始化,这就像您根本没有显式初始化基类一样,因此它被迫使用默认构造函数初始化它,而您没有默认构造函数。

最新更新