Почему нет необходимой квалификации?
ОК, я просто опубликую полную программу, даже если у нее есть посторонние вещи, и этот код - это мертвый код & hellip;
#include <iostream>
#include <fstream>
namespace detail {
// Solution by Johannes Schaub alias litb
// http://groups.google.com/group/comp.std.c++/browse_thread/thread/b567617bfccabcad
template<int> struct D {};
typedef char yes[1];
typedef char no[2];
template< class T, class U >
yes& f( int, D< sizeof T(*(U*)0) >* = 0 );
template< class T, class U >
no& f( ... );
template< class To, class From >
struct IsExplicitlyConvertible
{
enum{ yes = (sizeof detail::f< To, From >(0) == sizeof( detail::yes ) ) };
};
bool const streamsSupportWindows =
IsExplicitlyConvertible< std::ofstream, wchar_t const* >::yes;
}
class InFStream
: public std::ifstream
{
public:
InFStream() {}
explicit InFStream(
char const* filename,
ios_base::openmode mode = ios_base::in | ios_base::out
)
: std::ifstream( filename, mode )
{}
};
int main()
{
using namespace std;
cout << (detail::streamsSupportWindows
? "Windows-enabled"
: "Ach, no Windows support"
) << endl;
}
Это компилируется с MSVC и g++. Но в классе InFStream
почему мне не нужно квалифицировать ios_base
? Или, действительно, тот же вопрос, почему мне нужно использовать std::
квалификацию ifstream
в списке инициализаторов конструктора?
Ответы
Ответ 1
Некоторые мысли о том, почему вы должны указать std::ifstream
в инициализаторе конструктора.
Я думаю, что typedef
является виновником - ifstream
определяется как typedef basic_ifstream<char, char_traits<char> > ifstream;
). Если вы измените свой конструктор на
explicit InFStream(
char const* filename,
ios_base::openmode mode = ios_base::in | ios_base::out
):
basic_ifstream<char,std::char_traits<char>>( filename, mode ){}
вам также не нужно указывать std::basic_ifstream
. Я не могу найти информацию о том, почему typedef
работает таким образом, но проблема воспроизводима. Например,
namespace test1
{
class A {
public :
static const int cn = 1;
virtual ~A();
A(int t): x(t){};
int x;
};
class B:public A
{
public:
B(int t) : A(t){};
};
typedef B XX;
};
class C:public test1::XX
{
int aaa;
public:
explicit C(int x) :XX(x) // error
explicit C(int x) :test1::XX(x) // ok
explicit C(int x) :B(x) // also ok
{
aaa = A::cn;
};
};
Ответ 2
Разница в том, что ifstream
не отображается как имя введенного класса, потому что это имя typedef
, а не имя class
. Таким образом, это не является видимым неквалифицированным как введенное имя класса из базового класса.
ios_base
- это подлинное имя класса, которое является базовым классом (базового класса) класса, в котором оно используется, и поэтому оно является неквалифицированным как имя класса инъекции.
например.
namespace X
{
class A {};
template<class> class Z {};
typedef Z<char> B;
}
class C : public X::A
{
C() : A() {} // OK, A is visible from the base class
};
class D : public X::B
{
D() : B() {} // Error, B is a typedef,
// : X::B(), : Z<char>() or even : Z() can be used.
};
В вашем примере вместо std::ifstream
вместо него можно использовать неквалифицированный basic_ifstream
. (Или basic_ifstream<char>
или basic_ifstream<char, std::char_traits<char> >
, но они на самом деле не сохраняют никакой типизации или большей ясности справки.)
Ответ 3
Другое наблюдение заключается в том, что ios_base:: openmode работает, но ios:: openmode не делает:
class InFStream
: public std::ifstream
{
// ...
ios::openmode m1; // error: ios does not name a type
ios_base::openmode m2; // ok
}
Я думаю, что a1ex07 нашел суть вопроса: здесь снова ios_base
- это имя класса, а ios
- просто typedef.
И разница в том, что имя класса является членом этого класса (9/2), и поэтому его можно искать как имя типа в InFStream
(3.4.1/7, пункт 1) так как он является членом базового класса InFStream
. Но некоторые typedef просто рядом с базовым классом в другом пространстве имен не видны.
[Номера стандартных разделов из С++ 98.]
Ответ 4
Когда вы выходите из класса, который вы указали
std::ifstream
чтобы иметь возможность найти класс в пространстве имен std.
В самом коде вы, класс, полученный из std:: ifstream, знает все об ifstream.
Наследование ifstream:
ios_base -> ios -> istream -> ifstream