質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

5回答

12547閲覧

[C++] あるクラスをある名前空間に入れる時の、ヘッダファイルの書き方

yama_da

総合スコア73

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2017/03/14 23:46

編集2022/01/12 10:55

こんにちは。どうでも良いことだと言われればそれまでの事なのですが、気になったので質問させてください。

Hogeクラスを名前空間BokeBokeに入れたいと思ったら、

C++

1//Hoge.h 2namespace BokeBoke 3{ 4 class Hoge 5 { 6 //いろいろ... 7 }; 8} /* namespace BokeBoke */

のように書きますよね?しかしこれだとインデントが1つ増えてしまい、僕はこれが嫌で、

C++

1//hoge.h 2namespace BokeBoke 3{ 4 5class Hoge 6{ 7 //いろいろ... 8}; 9 10} /* namespace BokeBoke */

のようにインデントを1つ下げて書いていました。
が、ブロックが入れ子になっているのに { と { が縦に並んでいるのが気になってしまいます。そこで、

c++

1//hoge.h 2namespace BokeBoke 3{ 4 class Hoge; 5} 6 7class BokeBoke::Hoge 8{ 9 //いろいろ... 10};

のように書けたらいいなと思って試してみると、コンパイルが通りました。しかし、このような書き方をしているコードを見かけたことはありません(人の書いたコードに触れたことがあまりないからかもしれませんが)。この書き方は、c++的にありなのでしょうか?特に、

C++

1class BokeBoke::Hoge

の部分が気になります。

よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答5

0

こんにちは。

しかしこれだとインデントが1つ増えてしまい、僕はこれが嫌

私も同じです。名前空間でインデントを消費するのって嫌ですよね。

名前空間の外側での定義はやったとこはないですが、MSVC 2015とMinGW 5.3.0では通りました。調べてみると大丈夫そうな感じです。

名前空間のメンバーは、名前空間の外側で定義することができる。

上記資料は、江添氏という方が執筆されたC++11規格書の解説ですので、恐らく規格書にも同様なことが書かれていると思います。

投稿2017/03/15 01:08

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yohhoy

2017/03/15 02:14

インデント問題であればコーディング規約や個人の趣味趣向になってしまいそうですが、個人的には名前空間(namespace)でのインデントは*しない*派です。他のライブラリでもあまり名前空間ごとに字下げはしていない気もしますが、好きなスタイルを採用すればよさそうですね。
Chironian

2017/03/15 02:52

私も名前空間でインデントしているライブラリはあまり見ない気がしますし、私もインデント*しない*派です。 とはいえ、同じくインデントしても問題ないと思います。
guest

0

のようにインデントを1つ下げて書いていました。

これは私は普通にやってますね。
boostとかでもやっているやつはありますね。

c++

1//hoge.h 2namespace hoge1{ 3namespace hoge2{ 4namespace hoge3{ 5 6class Hoge{ 7}; 8 9} 10} 11}

ちなみにVisual Studioだとオプションの
テキストエディター > C/C++ > 書式設定 > インデント
名前空間のインデントをする
をオフにすれば上記のような整形をしてくれます。

なお、c++17では上記は以下のように書けるようになります。

c++

1//hoge.h 2namespace hoge1::hoge2::hoge3{ 3 4class Hoge{ 5}; 6 7}

投稿2017/03/15 03:35

hmmm

総合スコア818

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

以下のコードはどこか別の所でBokeBoke::Hogeが宣言されているよ、というプロトタイプ宣言です。
class Hogeからは存在の情報だけが露にされているわけです。

C++

1namespace BokeBoke 2{ 3 class Hoge; 4}

これによって得られることは、BokeBoke::Hogeを識別できるようになることだけです。
そして、BokeBoke::Hogeが識別できて何がうれしいかというと、参照型ならアクセスできるようになります。

namespace BokeBoke { class Hoge; } void SomeFunction(BokeBoke::Hoge *p);

この宣言は可能です。
ただし、この宣言からインスタンス化は不可能ですし、できるのは参照の安全な受け渡しのみです。

このような記述は、ヘッダファイル内で別のヘッダファイルを読み込むのを抑制したい場合に役立ちます。
ある複数のモデルを扱うサービスがあったとして、複数のモデル全てをクライアントが使うとは限りません。その場合に、クライアントからサービスにアクセスするのに全てのモデルのヘッダファイルをインポートするのは賢い選択といえるでしょうか。

C++

1// hoge.h 2namespace Model 3{ 4 class Hoge 5 { 6 // ... 7 } 8} 9 10// service.h 11#include "hoge.h" 12#include "fuga.h" 13#include "piyo.h" 14 15class Service 16{ 17 void AddHoge(Model::Hoge *hoge); 18 Model::Hoge* GetHoge(int hoge_id); 19 20 void AddFuga(Model::Fuga *fuga); 21 Model::Fuga* GetFuga(int fuga_id); 22 23 void AddPiyo(Model::Piyo *piyo); 24 Model::Piyo* GetPiyo(int piyo_id); 25}

こう書かれているよりも以下のようにした方がスコープの穢れは少なくなります。

C++

1// service.h 2namespace Model 3{ 4 class hoge; 5 class fuga; 6 class piyo; 7} 8 9class Service 10{ 11 void AddHoge(Model::Hoge *hoge); 12 Model::Hoge* GetHoge(int hoge_id); 13 14 void AddFuga(Model::Fuga *fuga); 15 Model::Fuga* GetFuga(int fuga_id); 16 17 void AddPiyo(Model::Piyo *piyo); 18 Model::Piyo* GetPiyo(int piyo_id); 19}

C++

1// client.cpp 2#include "service.h" 3#include "hoge.h" 4 5void Client::SomeFunction(int id) 6{ 7 Model::Hoge *hoge = service->GetHoge(id); 8 // do something here 9}

上記はとても簡単なサンプルですが、プロトタイプ宣言の意味はなんとなくわかると思います。
特にヘッダファイルの更新によるオブジェクトファイルのリビルドを抑制することができます。
後者のサンプルであれば"fuga.h/piyo.h"の更新時にclient.cppがリビルドされることはありません。
特に古い巨大なモノリシックアプリケーションでは、このテクニック一つでコンパイル時間がずっと変わってきます。


僕はというと、ヘッダファイル内での名前空間はインデントする派です。
cppファイル内ではしません。cppファイルでは多くても名前空間の宣言は一種類で、それが無名名前空間の宣言だからです。
インライン関数用のファイルでは名前空間を直接記述することがないので当然インデントしません。

(追記:ヘッダファイルは体外的なところで、原則マイルールを適用せず、読みやすく、クリーンで、情報は多くても実コードの少ないファイルにしたいと考えています。一方でCPPファイルは編集時の快適さを求めており、関数の記述開始地点から終了地点までしかファイルを読まない=インデントが無いのが自然と考えているため、ボディとヘッダで違うルールを適用しています。)

// ヘッダファイル namespace Name { class Hoge { private: void Fuga(); void Piyo(); }; } // インライン関数群 void Name::Hoge::Fuga() { // ... } // CPPファイル namespace { // ここではインデントしていない void SomeFunction() { } } // end of namespace void Name::Hoge::Piyo() { // ... }

投稿2017/03/15 03:15

編集2017/03/15 03:31
haru666

総合スコア1591

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ご利用のC++コンパイラは何でしょうか?名前空間内でクラスを宣言する場合、あなたの書き方はC++仕様的に許容されません。少なくともGCCとClangでは下記コードはコンパイルエラーとなります。

C++

1namespace BokeBoke 2{ 3 4class BokeBoke::Hoge // NG: "class Hoge"が正しい 5{}; 6 7} /* namespace BokeBoke */

投稿2017/03/15 00:45

yohhoy

総合スコア6189

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Chironian

2017/03/15 01:10

この記述は、yama_daさんの記述ミスのような気がします。
yama_da

2017/03/15 02:09

回答ありがとうございます。 Chironianさんのおっしゃる通り、記述ミスでした。 ご指摘ありがとうございます。
yama_da

2017/03/15 02:10

[追記] 使用したコンパイラは gcc version 5.4.1 20160904 (Ubuntu 5.4.1-2ubuntu1~16.04) です。
guest

0

二つは違うクラスになっていませんか?
using を使いましょう。

無名の名前空間

追記

ぼやっとしていて何と勘違いしたのか意味不明なことを書きました。
全面撤回します。

投稿2017/03/15 00:01

編集2017/03/15 00:17
Zuishin

総合スコア28656

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問