2011-10-23 2 views
13

좋아, 나는 그것이 단지 불필요한 물건을 가지고 있고 문제의 코드가 죽은 코드 & 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을 수혜 할 필요가없는 이유는 무엇입니까? 또는 동일한 질문을 정말로 자격을 ifstream 생성자 초기화 프로그램 목록에 사용해야합니까?

+2

ifstream은 std 네임 스페이스에 있기 때문에? 왜 당신이 그것을 사용할 필요가 없다고 생각합니까? –

+2

@VJo :'ios_base'도'std' 네임 스페이스에 있습니다. 내가 언급 한 컴파일러가이 코드를 잘 컴파일한다고 생각하는 이유는 그것이 그렇기 때문입니다. ㅎ. –

+4

InFStream 클래스가 std :: ifstream에서 상속 받았기 때문에 std :: ios_base에서 상속받을 가능성이 있습니다. 따라서 모든 ios_base 열거 형은 상속을 통한 클래스의 멤버이므로 완전한 자격이 필요하지 않습니다. – Praetorian

답변

6

일부의 생각. typedef이 범인이라고 생각합니다. ifstreamtypedef 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; 
}; 
}; 
+0

나는 "솔루션"이라는 대답을 임의로 선택해야했지만,이 대답은'typedef' 문제를 지적한 첫 번째 질문이었습니다. –

+0

그리고 덧붙이면,': basic_ifstream (filename, mode) {}'라고 쓸 수 있습니다. 템플릿 인수 목록이 필요하지 않습니다 (gcc4.5부터 시작하여 gcc가 마침내 이것을 올바로 가져옵니다). –

0

당신은

std::ifstream 

는 표준 네임 스페이스의 클래스를 찾을 수 있도록 지정 당신이 가지고있는 클래스에서 파생합니다.

코드에서 std :: ifstream에서 파생 된 클래스는 ifstream의 모든 것을 알고 있습니다. ifstream의

상속 : 당신은 생성자의 초기화에 std::ifstream을 지정해야하는 이유에 대해

ios_base -> ios -> istream -> ifstream 
+0

'ios_base'는 무엇인가요? 또한'std' 네임 스페이스에있다. –

+0

네, ifstream의 기본 클래스 – Totonga

7

차이는 그것이 typedef 이름 아닌 class 이름이므로 ifstream가 주입 클래스 이름으로 표시되지 않는 것이있다. 따라서 기본 클래스에서 주입 된 클래스 이름으로 정규화되지 않은 것으로 표시되지 않습니다.

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> > 그러나이 정말 어떤 입력을 저장하거나 전혀 선명도를 도움이되지 않습니다.)

4

또 다른 관찰되는 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는 볼 수 없습니다.

[표준 섹션 번호는 C++ 98입니다.]

관련 문제