ヘッダオンリーライブラリでプライベートなnamespaceメンバを実現する方法はありますか?

このQ&Aのポイント
  • ヘッダオンリーライブラリでプライベートなnamespaceメンバを実現する方法はありますか?
  • 無名名前空間を使用する方法では、Hoge::hogeHelperとしてアクセスできてしまいます。
  • ライブラリを書き換えない限り、hogeHelperへのアクセスを禁止する方法はありませんか?
回答を見る
  • ベストアンサー

privateなnamespaceメンバ

namespace内のメンバをprivateのようにしたいときは、無名名前空間を使うとあったのですが、ヘッダオンリーライブラリでこれを実現する方法はありませんか? 紹介されている方法 //hoge.h namespace Hoge{ void hoge(); } //hoge.cpp namespace Hoge{ namespace{ void hogeHelper(){} } void hoge(){hogeHelper();} } 上記の方法ではhoge.cpp以外からはhogeHelperにはアクセスできなくなるとのことです。 しかし、ヘッダオンリーライブラリで次のように書いている場合にHoge::hogeHelperとしてアクセスできてしまいます。 //hoge.h namespace Hoge{ namespace{ inline void hogeHelper(){} } inline void hoge(){hogeHelper();} } (ライブラリを書き換えない限り)hogeHelperへのアクセスを禁止する方法はありませんか?

質問者が選んだベストアンサー

  • ベストアンサー
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.3

まあこの筋だとどうやっても「エラーメッセージがわけわからん」状態になるのは避けられないでしょうねぇ. ソースで #define DO_NOT_USE_AFTERWARD(name) なんか のようなマクロを定義して明確にすれば多少「ごまかし」感は減るけど.... あるいは, いっそあきらめて すべてのメンバーが private かつ static な class を作るとか. たとえば, namespace Hoge { void hoge(); class detail { static void hogeHelper() { } friend void hoge(); }; inline void hoge() { detail::hogeHelper(); } } みたいなイメージ.

haporu
質問者

補足

クラスのprivate staticメンバにしてfriend指定するのは思いつきませんでした。 これならエラーメッセージも理解しやすいです。 namespace Hoge内の他の関数やhoge()内から頻繁に使用される共通処理hogeHelper()を単体で外部から呼び出されたくないだけなので、classのprivate staticメンバで十分目的が果たせます。 namespaceのようにメンバを分割して記述できないことと、class名::を書くことを我慢すれば、namespaceにこだわる必要はないですね。 ありがとうございました。

その他の回答 (2)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

手元の g++ で試してみると namespace Hoge{ namespace{ inline void hogeHelper(){} } inline void hoge(){hogeHelper();} namespace{ inline namespace { void hogeHelper(); } } } で (「エラーになる」という意味で) 回避できている感じがします. つまり C++0x ならごまかせるかもしれない. そもそも名前空間が「アクセス制御」を意図しているわけじゃないので, 結局は「ごまかし」の感じが強いですが.

haporu
質問者

補足

hoge()内では1つめのhogeHelper()を参照しつつ、外からは定義されていない2つめのhogeHelper()を参照させるということですね。 inline namespaceはVC++2010ではエラーになってしまいました。 inlineを外した所、外からも1つめのhogeHelper()を参照してしまったらしく、リンクも通ってしまいました。 ここで、2個目のhogeHelper()をnamespace{namespace{}}から外に出してHoge内にしたところ、hoge()からは無名1つめのhogeHelper()を参照し、外からは2つめのhogeHelper()を参照したようで、みごとにリンクエラーにできました。 これはなかなかスマートな方法です。 さらに、リンクエラーではなくコンパイルエラーにするために、2つめのhogeHelper()を、もはや関数ではなく何でも良いのでnamespaceにしてしまいました。 namespace hogeHelper{} これでHoge::hogeHelperによる関数へのアクセスを完全に禁止できそうです。 ありがとうございました。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

可能なら #define hogeHelper という技でごまかすとか.

haporu
質問者

補足

なるほど、そういう手もあるんですね。 回答ありがとうございます。

関連するQ&A

  • クラスを公開する部分を制限するには?

    以下の例のようなクラスを書きました。 ========================== #include<Hoge.h> class Moge{ public:  int getCountHoge(void); private:  Hoge* d; }; ========================== これをライブラリとして、他の人に使ってもらうように 公開しようと考えています。 ただ、上記のままヘッダーファイルを配ってしまうと、 使用者にとって不要だと思われる Hoge.h の include が 発生してしまいます。 実際には、Hoge.h は 他のクラスを使用したり、 inline 関数などを多用した少々重い実装となっています。 なんらかの方法で、これを抑制できないでしょうか? 試しに以下のようにprivate 部分を削除したヘッダーファイルを 公開用に別途用意してみましたが、実行時エラーとなってしまいました。 (ライブラリコンパイル時は元のヘッダーファイルを使用して、 使用者側ソースは下記ヘッダーファイルを使用しました。) ========================== class Moge{ public:  int getCountHoge(void); }; ========================== よろしくお願いします。

  • 名前空間でビルドエラー(LNK2005)

    C++の名前空間について勉強しています。 ソースを組んでビルドしようとしたところ、以下のようなエラーが表示されました。 > error LNK2005 "int test::count" は既に main.obj で定義されています。 > fatal error LNK1169: 1つ以上の複数回定義されているシンボルが見つかりました。 変数が多重定義(?)されているというエラーであることはわかるのですが、 その対処法が分からず困っています・・・。 わかる方がいればアドバイスください。 よろしくお願いします。 --------------------------------------- ○main.cpp #include "ns.h" int main(){  test::hoge(); } ○ns.h #pragma once namespace test {  int count;  void hoge(); } ○ns.cpp #include <iostream> #include "ns.h" void test::hoge(){  std::cout << "hoge()が呼ばれた" << test::count++ << "回目" << std::endl; }

  • [VC++]ヘッダファイルからの関数コール

    Formのボタンクリックイベント(Form.h)から 別ファイル(.cpp)の関数をコールしたいのですがうまくいきません、 どのようにすればよいでしょうか?ご教授お願いします。 1> : error C2144: 構文エラー : 'void' は ')' によって先行されなければなりません。 1> : error C2059: 構文エラー : ')' //----- main1.h #include <stdio.h> #include "Form1.h" namespace A { void main1(); } //----- main1.cpp #include <stdio.h> #include "main1.h" using namespace A; void main1() { //処理 } //----- Form1.h #include <stdio.h> #include "main1.h" void main1(void); namespace A { public ref class Form1 : public System::Windows::Forms::Form { public: private: System::Void btn_Click(System::Object^ sender, System::EventArgs^ e) { //★クリックイベントからmain1の関数コールしたい main1(void); } }; }

  • フォームプログラムでのファイル分割

    先日よりお世話になっています。VC++フォームプログラムのスコープに関する質問です。 フォームプログラムではデザイナモードでGUIで作成したデザインや割り込み、プロパティなどが、自動的にソースとして全てForm1.hに作成されます。さらに自分で処理を追加していくわけですが、Form1.hが膨大になってしまうこともあり、デザインに関する部分以外を別のファイルanother.cppで書きたいのですがうまくいきません。どうか知恵をお貸しください。 まず、現在のForm1.hの構成は、 --Form1.h----------------------------------------------------- namespace namForm1{ class Form1{ private: void func(); //プロトタイプ ・・・・・・・・ } ・・・・・ } void namForm1::Form1::func(){・・・} //関数定義 --------------------------------------------------------------- のようになっており、ここでフォームプログラムの処理が全て記載され、実質のメインともいえるような作りになっています。 ですが、Form1.hのコード量が増えて見辛くなることを嫌って、Form1.hで書いてある関数func()などを内容をanother.cppに出したいのです。another.cppからnamForm1の名前空間を使おうとしても、当然「識別子がクラス名でも名前空間名でもありません。」怒られますし、another.cppにForm1.hをインクルードしてもやはり、「識別子がクラス名でも名前空間名でもありません。」となります。このプログラムをスマートにファイル分割する方法を教えてください。お願いします。

  • ヘッダーファイルのインクルード

    VC++6.0です。 ヘッダーファイルをincludeしていいかどうかは どのように決まるのでしょうか? classは、appとhogeの1種類があるとして、 app.h、app.cppとhoge.cpp、hoge.hの4つのファイルがあるとします。 1)appによるhogeのメンバの操作があって、その逆は無い場合 2)hogeもappのメンバを操作する場合 のそれぞれで教えてください。 最初、私は、そのclass内で別のclassのメンバ関数を 呼ぼうと呼ぶまいとincludeしてもかまわないと思っていました。 しかし、自分の作ったプログラムを検討したところ 1)の場合で、hogeのヘッダーに #include "app.h"と入れるとエラーになります。 hogeのcppファイルに#include "app.h"と入れてもエラーになります。

  • 無名ネームスペース中のstatic宣言について

    お世話になります。 以下のように無名ネームスペース内でstatic定数を宣言することに 何か問題はあるでしょうか? QACという静的コードチェックツールで 「無名ネームスペース中のstatic宣言」と 警告が出てしまいます。 test.h ----------------------- class Test{ void testFunc(); }; test.cpp ------------------------ namespace { static const int i = 3; } void Test::testFunc(){ std::cout << i << std::endl; }

  • ヘッダファイルの有効範囲

    現在OpenGLを使ったプログラムを作っていて, hoge.hというヘッダファイルで #include <GL/glut.h> piyo.hというヘッダファイルには #include "hoge.h" そしてさらにhogehoge.hというヘッダファイルに #include "piyo.h" として, hogehoge.cppのソースファイルにて #include "hogehoge.h"してOpenGLの関数を使おうとしたら エラーが出ました. hogehoge.cppでhogehoge.hをインクルード →hogehoge.hでpiyo.hをインクルード →piyo.hでhoge.hをインクルード →hoge.hでGL/glut.hをインクルード というように,橋渡し的にインクルードはできないのでしょうか? これはこのような仕様なのでしょうか? それとも他に誤りがある可能性があるのでしょうか… 非常に困っております. ご回答お待ちしております.

  • 別スレッドからメインスレッドのテキストボックスに文字を表示させたい

    Visual C++ 2005 Express Editionを使用している初心者です。 タイトルの方法がどうしてもわからないので教えてください。 うまく説明できないので聞きたいところのコードを載せます。 //SAMPLE.cpp #include "stdafx.h" #include "Form1.h" using namespace SAMPLE; int main(array<System::String ^> ^args) { Application::EnableVisualStyles(); Application::SetCompatibleTextRenderingDefault(false); Application::Run(gcnew Form1()); } //Form1.h #include <process.h> #include <vcclr.h> namespace SAMPLE { unsigned __stdcall counter(void *arg); int thread_id1; unsigned dummy; using namespace System; using namespace System::ComponentModel; using namespace System::Collections; using namespace System::Windows::Forms; using namespace System::Data; using namespace System::Drawing; public ref class Form1 : public System::Windows::Forms::Form { public:Form1(void) { InitializeComponent(); //別スレッド起動 thread_id1=_beginthreadex(NULL,0,counter,(void *)1,0,&dummy); } private: System::Windows::Forms::TextBox^ textBox1; private: System::ComponentModel::Container ^components; void InitializeComponent(void) { this->textBox1 = (gcnew System::Windows::Forms::TextBox()); //省略(コンポーネント初期化) } private: System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e) { } }; unsigned __stdcall counter(void *arg){ //別スレッド //ここで文字列を記述して上のtextBox1に表示したい return 0; } } 初歩的なことかもしれませんが、 よろしくお願いします。

  • static と externについて

    以下のようなプログラムを組んでいます。 //main.h static int hoge; void someOperation(); //hoge.cpp #include "main.h" extern int hoge; void someOperation() { hoge = 15; } //main.cpp #include <stdio.h> #include "main.h" extern int hoge; int main() { someOperation(); printf("%d\n",hoge); return 0; } このプログラムを実行したのですが、自分の予想した15という出力ではなく、不定値になるようなのです。 自分の予想では、someOperationで操作するhogeも、main内で操作するhogeも同じになるようにと思いexternをつけているのですが、なにがまずいのでしょうか? ご存知の方、ご教授お願いします。

  • gdbで無名名前空間の関数にブレイクポイント

    Windows+cygwin+emacsでc++のプログラムを勉強しています。デバッガとしてemacs上でgdbを使っているのですが、無名の名前空間にある関数にブレイクポイントを設定する方法がわかりません。例えば、 namespace {  void foo() {    ...  } } int main(void) {  foo(); } のようなfoo.cppファイルをコンパイルしてfoo.exeファイルを作り、それをgdbによりデバッグするとします。そこで、gdb上で b main とすると、mainに入ったところにブレイクポイントが設定されますが、 b foo としても、Function "foo" not defined.と表示されてブレイクポイントが設定されません。無名の名前空間にある関数にはどのように入力してブレイクポイントを設定するのでしょうか。とりあえず、今は行番号によりブレイクポイントを設定しています。ご存じの方がいらっしゃいましたら、ご教授ください。お願いします。

専門家に質問してみよう