为什么没有include语句成功编译头文件?

时间:2014-08-11 14:06:03

标签: c++ include

以下代码编译成功,但我认为它缺少#include<string>,为什么? 如果我只包含字符串而不是向量,则会失败。有人可以解释一下吗?

StrBlob.hpp:

#ifndef STRBLOB_H_ 
#define STRBLOB_H_ 
#include <vector> 
class StrBlob { 
 public: 
    typedef std::vector<std::string>::size_type size_type; 
    StrBlob(); 
    StrBlob(std::initializer_list<std::string> i1); 
    bool empty() const {return data->empty();} 
    void push_back(const std::string &s) {data->push_back(s);} 
    void pop_back(); 
    std::string &front(); 
    std::string &back(); 
 private: 
    std::shared_ptr<std::vector<std::string>> data; 
    void check(size_type i, const std::string &msg) const; 
}; 
#endif

编译:

g++ StrBlob.hpp

我只编译这个文件而没有其他文件。它编译成功。

更新

如果我添加一个主文件:

main.cc

#include "StrBlob.hpp"
int main() {
    int i = 0;
    return 0;
}

只是这样做:

g++ main.cc

失败了。编译输出:

In file included from test_strblob.cc:1:
In file included from ./StrBlob.hpp:3:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/vector:1540:9: error: implicit
      instantiation of undefined template 'std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >'
        ++this->__end_;
        ^
./StrBlob.hpp:11:49: note: in instantiation of member function 'std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>,
      std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >
      >::push_back' requested here
    void push_back(const std::string &s) {data->push_back(s);}
                                                ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/iosfwd:188:33: note: template is declared
      here
    class _LIBCPP_TYPE_VIS_ONLY basic_string;
                                ^
In file included from test_strblob.cc:1:
In file included from ./StrBlob.hpp:3:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/vector:265:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/__bit_reference:15:

▽
  3 #ifndef STRBLOB_H_
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/algorithm:627:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/memory:1641:31: error: implicit

▽
      instantiation of undefined template 'std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >'
            ::new((void*)__p) _Up(_VSTD::forward<_Args>(__args)...);
                              ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/memory:1568:18: note: in instantiation of
      function template specialization 'std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>
      > >::construct<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, const std::__1::basic_string<char,
      std::__1::char_traits<char>, std::__1::allocator<char> > &>' requested here
            {__a.construct(__p, _VSTD::forward<_Args>(__args)...);}
                 ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/memory:1449:14: note: in instantiation of
      function template specialization 'std::__1::allocator_traits<std::__1::allocator<std::__1::basic_string<char,
      std::__1::char_traits<char>, std::__1::allocator<char> > > >::__construct<std::__1::basic_string<char, std::__1::char_traits<char>,
      std::__1::allocator<char> >, const std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > &>' requested
      here
            {__construct(__has_construct<allocator_type, pointer, _Args...>(),
             ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/vector:1538:25: note: in instantiation of
      function template specialization 'std::__1::allocator_traits<std::__1::allocator<std::__1::basic_string<char,
      std::__1::char_traits<char>, std::__1::allocator<char> > > >::construct<std::__1::basic_string<char, std::__1::char_traits<char>,
      std::__1::allocator<char> >, const std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > &>' requested
      here
        __alloc_traits::construct(this->__alloc(),
                        ^
./StrBlob.hpp:11:49: note: in instantiation of member function 'std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>,
      std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >
      >::push_back' requested here
    void push_back(const std::string &s) {data->push_back(s);}
                                                ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/iosfwd:188:33: note: template is declared
      here
    class _LIBCPP_TYPE_VIS_ONLY basic_string;
                                ^
2 errors generated.

需要#include <string>。我想原因可能就像彼得克拉克所说的那样。

3 个答案:

答案 0 :(得分:4)

C ++预处理器基本上采用了所有#include指令,并基本上将它们粘贴到编译器的一个长流中。

你可能没有把它包含在这里,但它可能包含在其他地方之前。但是,为了正确,您也应该包括它。创建隐式依赖项可能会使您的代码难以维护和脆弱(当涉及到构建错误时),因此在您看到它们的任何地方都要避免使用它们。

答案 1 :(得分:4)

在某些平台上,某些系统标头将包含其他平台不包含的文件。在任何版本的MSVC上,我使用<vector>包括<string>。在GCC - 根据我的经验 - 它不会这样代码不会编译。通常,您希望确保包含您使用的所有内容,即使它没有编译。

要查看编译器是否属于这种情况,您可以将preprocesser输出保存到文件中(例如,this is how you do it in GCCMSVC)。然后,您可以搜索basic_string并查看它的来源。在我的MSVC案例中:

#line 7 "w:\\program files (x86)\\microsoft visual studio 12.0\\vc\\include\\vector"
#line 1 "w:\\program files (x86)\\microsoft visual studio 12.0\\vc\\include\\stdexcept"

#line 1 "w:\\program files (x86)\\microsoft visual studio 12.0\\vc\\include\\xstring" 

您可以看到vector包含stdexcept,其中包含xstringimplementation of std::basic_string is defined for MSVC

请注意,你也可以只查看标准标题,但它可能隐藏在某个不明显的地方(我不希望它通过<stdexcept>)。

故事的寓意是,即使它编译,也要确保你总是包括你使用的东西,以避免在后面遇到问题(这包括文件一般,而不仅仅是标准库)。

对更新的响应

正如其他人所说的那样,所有#include所做的都是必须粘贴include指令所在的头文件中的代码。所以在预处理之后(当包含“粘贴”时),编译器将看到的是:

// contents of <vector> header would be pasted here

class StrBlob { 
 public: 
    typedef std::vector<std::string>::size_type size_type; 
    StrBlob(); 
    StrBlob(std::initializer_list<std::string> i1); 
    bool empty() const {return data->empty();} 
    void push_back(const std::string &s) {data->push_back(s);} 
    void pop_back(); 
    std::string &front(); 
    std::string &back(); 
 private: 
    std::shared_ptr<std::vector<std::string>> data; 
    void check(size_type i, const std::string &msg) const; 
};

int main() {
    int i = 0;
    return 0;
}

之前和现在之间的主要区别在于,您现在链接以及编译。虽然我真的不确定它究竟是什么导致了这一点,但在我看来这不值得知道,因为它只是编译器标准库的一个实现细节。

要知道的主要事项是始终包含您使用的内容(您<memory>也缺少std::shared_ptr)。 哪些系统标题可能包含或不包含依赖于实现,因此不应该依赖或(希望)需要担心。

答案 2 :(得分:0)

这可能会编译,因为包含的代码如下所示:

#include <string>
// ...
#include "strblob.h"
// ...

包含标头是在编译器进入之前由预处理器完成的纯文本操作,因此strblob.h内的代码将看到<string>的内容。不过,人们不应该依赖那些“幸运”的间接依赖。