Подтвердить что ты не робот

Почему нет необходимой квалификации?

ОК, я просто опубликую полную программу, даже если у нее есть посторонние вещи, и этот код - это мертвый код & 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 в списке инициализаторов конструктора?

4b9b3361

Ответ 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