OK, I'll just post the complete program even though it has extraneous stuff and the code in question is the dead code…
#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;
}
This compiles fine with MSVC and g++. But in the InFStream
class, why do I not need to qualify ios_base
? Or, same question really, why do I need to use std::
qualification of ifstream
in the constructor initializer list?
Qualifications show your knowledge and skills building in a specialist subject. If you achieve a qualification in a specialist subject like engineering, employers know you have developed not just the life skills but also the concrete knowledge they need to offer you the job.
Qualifications are more important The benefits affect all parts of life; intellectual, social, sporting, personal, artistic, ethical, and so much more. Recruiters often write job advertisements that specify that a degree is needed for the job, thus the market decides on this point, and it values degrees.
Employers prefer diploma-holders This is because your qualifications give employers an idea of what you know and are capable of accomplishing. The better credentials you have, the greater the likelihood that you can deliver the output they will require of you.
The difference is that ifstream
isn't visible as an injected class name because it is the name of a typedef
, not the name of the class
. It isn't therefore visible unqualified as an injected class name from the base class.
ios_base
is a genuine class name which is a base class (of a base class) of the class where it is used and so is visible unqualified as an inject class name.
E.g.
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.
};
In your example, instead of std::ifstream
, you can use unqualified basic_ifstream
instead. (Or basic_ifstream<char>
or basic_ifstream<char, std::char_traits<char> >
but these don't really save any typing or help clarity at all.)
Some thoughts about why you have to specify std::ifstream
in constructor's initializer .
I think typedef
is the culprit - ifstream
is defined as typedef basic_ifstream<char, char_traits<char> > ifstream;
). If you change your constructor to
explicit InFStream(
char const* filename,
ios_base::openmode mode = ios_base::in | ios_base::out
):
basic_ifstream<char,std::char_traits<char>>( filename, mode ){}
you also don't have to specify std::basic_ifstream
. I cannot find details about why typedef
works this way, but the problem is reproducible. For instance,
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;
};
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With