以下代码编译成功,但我认为它缺少#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>
。我想原因可能就像彼得克拉克所说的那样。
答案 0 :(得分:4)
C ++预处理器基本上采用了所有#include
指令,并基本上将它们粘贴到编译器的一个长流中。
你可能没有把它包含在这里,但它可能包含在其他地方之前。但是,为了正确,您也应该包括它。创建隐式依赖项可能会使您的代码难以维护和脆弱(当涉及到构建错误时),因此在您看到它们的任何地方都要避免使用它们。
答案 1 :(得分:4)
在某些平台上,某些系统标头将包含其他平台不包含的文件。在任何版本的MSVC上,我使用<vector>
包括<string>
。在GCC - 根据我的经验 - 它不会这样代码不会编译。通常,您希望确保包含您使用的所有内容,即使它没有编译。
要查看编译器是否属于这种情况,您可以将preprocesser输出保存到文件中(例如,this is how you do it in GCC和MSVC)。然后,您可以搜索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
,其中包含xstring
,implementation 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>
的内容。不过,人们不应该依赖那些“幸运”的间接依赖。