2011-10-23 42 views
13

好的,我只是发布完整的程序,即使它有无关的东西,并且所讨论的代码是死代码。为什么没有必要的资格?

#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?或者,同样的问题,为什么我需要在构造函数初始化列表中使用ifstreamstd::资格?

+2

因为'ifstream'是在std命名空间中吗?你为什么认为你不需要使用它? –

+2

@VJo:'ios_base'也在'std'命名空间中。至于为什么我认为我提到的编译器编译这些代码很好,那是因为他们这样做。嘿。 –

+4

可能是因为您的InFStream类继承自std :: ifstream,而std :: ifstream又继承自std :: ios_base。因此,所有的ios_base枚举都是通过继承的类的成员,并且不需要完全限定。 – Praetorian

回答

6

为什么你在构造函数初始化指定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; 
}; 
}; 
+0

我不得不随意选择一个答案是“解决方案”,但我认为这个答案是第一个指出'typedef'问题。 –

+0

另外,你可以写':basic_ifstream(filename,mode){}'。不需要模板参数列表(从gcc4.5开始,gcc终于可以正确地得到这个)。 –

0

当你从有类派生指定

std::ifstream 

能够找到std名称空间中的类。

在代码本身中,您从std :: ifstream派生的类知道ifstream的所有内容。

继承ifstream的的:

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

'ios_base'是什么?它也存在于'std'命名空间中。 –

+0

是的,但它的基础类ifstream – Totonga

7

不同的是,ifstream不作为注入的类名称可见,因为它是一个typedef的名称,而不是class的名称。因此它不可视为基类中的注入类名。

ios_base是一个真正的类名,它是使用它的类的基类(基类),因此可视为不合格的注入类名。

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. 
}; 

在你的榜样,而不是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。]

相关问题