C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

.hppでincludeしても.cppで再度include?

[トピック内 6 記事 (1 - 6 表示)]  << 0 >>

■95561 / inTopicNo.1)  .hppでincludeしても.cppで再度include?
  
□投稿者/ marusa (12回)-(2020/08/18(Tue) 08:27:22)

分類:[C/C++] 

2020/08/18(Tue) 08:29:39 編集(投稿者)

お世話になっております。
VisualStudio2015 c++を利用しております。

タイトルについて、以下のようにヘッダファイル(.hpp)とソースファイル(.cpp)を用意した場合、ヘッダでincludeしたものはソースでのincludeは不要だと考えていたのですが
ビルド時に未定義であることのエラーが出てしまいました。

<foo.hpp>
#ifndef foo
#define foo

#include <string>

... //stringを引数に持つ関数定義 等

#endif
</foo.hpp>

<foo.cpp>
#include "foo.hpp"

std::string str; // string: stdのメンバーではありません C2039 のエラー
</foo.cpp>

ヘッダとソースは同じ階層に配置しており、ヘッダがincludeされていない訳ではなさそうなのですが
ヘッダでincludeしてもソースでは再度includeが必要なのでしょうか?

初歩的な質問で申し訳ございません。よろしくお願いいたします。

//追記
ビルド時の拡張子は.libです。
ソースコードを書く際にはエラーの表記は特に出ていません。
引用返信 編集キー/
■95563 / inTopicNo.2)  Re[1]: .hppでincludeしても.cppで再度include?
□投稿者/ 774RR (819回)-(2020/08/18(Tue) 09:23:53)
普通に #include を使えば何も問題ないはずで、実際、ウチでは問題にならないっす。 i.e;
ヘッダファイル foo.h 中で #include <string> してるとき
ソースファイル foo.cpp が #include <foo.h> したら std::string は使える。

インクルードガードの foo がスペルが短すぎ&一般名詞すぎなので、
どこか別の場所で #define foo しているに1票
(特にプロジェクトのプロパティで設定できるコンパイルオプションで定義されている)

Visual Studio 限定でよければ #pragma once に書き換えちゃうとか
インクルードガード名はもっと長くしてかぶらないようにするとか
#if !defined(FOO_HPP_IS_ALREADY_INCLUDED)
#define FOO_HPP_IS_ALREADY_INCLUDED
#endif /* FOO_HPP_IS_ALREADY_INCLUDED)


引用返信 編集キー/
■95564 / inTopicNo.3)  Re[2]: .hppでincludeしても.cppで再度include?
□投稿者/ marusa (13回)-(2020/08/18(Tue) 09:47:08)
No95563 (774RR さん) に返信
回答ありがとうございます。

> インクルードガードの foo がスペルが短すぎ&一般名詞すぎなので、
> どこか別の場所で #define foo しているに1票
> (特にプロジェクトのプロパティで設定できるコンパイルオプションで定義されている)

確かに、インクルードガードが重複している可能性について考えていませんでした。
そこでヘッダの先頭を#pragma onceに変更してみたのですが、状況は変わらずでした。。
引用返信 編集キー/
■95565 / inTopicNo.4)  Re[3]: .hppでincludeしても.cppで再度include?
□投稿者/ 774RR (820回)-(2020/08/18(Tue) 11:02:43)
とりあえずヘッダ1個ソース1個で済む量なわけで、テスト用に新規プロジェクトを起こすのが吉。
あと cl.exe で手コンパイルできるなら「プリプロセッサだけ」結果を見るといろいろわかるかも。

#include は単純に読み込んだファイル内容をその場所に展開するだけなので
(別言語みたいにいろいろあっちへ飛びこっちを見てはやらない)
string は std のメンバではないエラーが出るのであれば原因は簡単
・ <string> を #include していない
・ <string> 自体のインクルードガードを自分で定義してる
くらいしかありえないです。

VS2019 の <string> は
C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.26.28801\include\string
というファイルなのでそれを見ると
_STRING_ というシンボル _STL_COMPILER_PREPROCESSOR というシンボルでガードしてるのがわかる。
この辺を自前で #define しちゃっていると誤動作するっす。

引用返信 編集キー/
■95568 / inTopicNo.5)  Re[4]: .hppでincludeしても.cppで再度include?
□投稿者/ marusa (14回)-(2020/08/18(Tue) 11:54:20)
No95565 (774RR さん) に返信
> とりあえずヘッダ1個ソース1個で済む量なわけで、テスト用に新規プロジェクトを起こすのが吉。
> あと cl.exe で手コンパイルできるなら「プリプロセッサだけ」結果を見るといろいろわかるかも。
>
> #include は単純に読み込んだファイル内容をその場所に展開するだけなので
> (別言語みたいにいろいろあっちへ飛びこっちを見てはやらない)
> string は std のメンバではないエラーが出るのであれば原因は簡単
> ・ <string> を #include していない
> ・ <string> 自体のインクルードガードを自分で定義してる
> くらいしかありえないです。
>
> VS2019 の <string> は
> C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.26.28801\include\string
> というファイルなのでそれを見ると
> _STRING_ というシンボル _STL_COMPILER_PREPROCESSOR というシンボルでガードしてるのがわかる。
> この辺を自前で #define しちゃっていると誤動作するっす。
>

詳細な解説ありがとうございます。
ターゲットをexeにした新規プロジェクトにて同じことをしたところ問題なく通すことが出来ました。
その後元のプロジェクトでいじっていたところ、(元の質問文でちゃんと書いておけという話なのですが)プリコンパイル済みヘッダを利用していたために影響が出ていたようでした。
情報不足で申し訳ありませんでした。
解決済み
引用返信 編集キー/
■95570 / inTopicNo.6)  Re[5]: .hppでincludeしても.cppで再度include?
□投稿者/ 774RR (821回)-(2020/08/18(Tue) 12:39:06)
Visual C/C++ のプリコンパイルヘッダの仕様はちょっとハマるところがあって

#include "stdafx.h"
#include <string>
の順なら正常動作する (<string> はプリコンパイルされずに普通に処理される) のに対して

#include <string>
#include "stdafx.h"
の順だと <string> はチャラになってしまう仕様

#include "stdafx.h" より前に書いた処理結果はすべて忘れ去られてしまうっス。
なので後者の書き方すると string は std のメンバじゃないエラーになるわけです。

今どきの開発マシンは十分高スペックなので、テストプログラムなんかだと
プリコンパイルヘッダを使わないほうがこの手の罠にはまらなくて楽できるですよ。
フルビルドに数分以上かかるような大規模プロジェクトだとプリコンパイルヘッダを慎重に使う
ことでビルド時間をかなり短縮できるので、うまく使い分けすると良いっスね。

解決済み
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ