トップページ⇒tech
1001コメント300KB

C++相談室 part17

■ このスレッドは過去ログ倉庫に格納されています
0001v(^・^)vNGNG
C++に関する質問はこちらへどうぞ。
ただし質問の前にFAQに一通り目を通してください。
また、テンプレートライブラリ(STL含む)に関する質問は
専用の別スレへどうぞ。

過去スレ、関連スレ、関連リンクなどはこちら>>2-15
0232228NGNG
>>230
でも、Koenigでやるのも地獄だし、誰かがstd::を付けたら
結局ダメだし。
0233名無しさんNGNG
ぬるぬるだな。
0234デフォルトの名無しさんNGNG
だな
0235デフォルトの名無しさんNGNG
企画違反でも入れちゃうのだっ
0236デフォルトの名無しさんNGNG
 イヤ〜ン
             ノ∩
           ⊂   ヽ ←>>233
            /( 。Д。 )っ
            U ∨ ∨
         ・@;∴‥
   ∧_∧ ∩  :: :.
  ( ・∀・)/  :: ::
  (つ   /  :: :'
  人⌒l ノ  :: :: ガッ
  し(_)
0237デフォルトの名無しさんNGNG
http://sourceforge.net/projects/opencxx/
これ、良いんじゃね?
0238名無しさん@EmacsNGNG
>>237
それ何?説明読んだけどイマイチ分からんかった。
C++の文法を拡張した物のC++へのトランスレーターって事?
0239デフォルトの名無しさんNGNG
ある関数 f があるとき、この関数を使って出来ることは

・fを呼び出す
・fのアドレスを取る

の2つだけである、ってのは正しいかな?
0240228NGNG
stdに入れるのがイレギュラーなのは確かだけど、だからといって
namespace myns {
  class Class1 { ... };
  swap(Class1 &x, Class1 &y) throw();
  ...

  namespace junk {
    using std::swap;
  }
  template <class Iter> void foo(Iter s, Iter e) {
    using namespace junk;
    Iter i1, i2;
    ...
    swap(*i1, *i2);
  }
}
なんて絶対やりたくないんだけど。
やっぱりオーバーロードしようとするのが間違い?
0241230NGNG
>>240
俺は常に.cppの頭でusing namespace std;する人なので
それは考えたことがなかった。。。けど、そんな複雑にせんでも

template <class Iter> void foo(Iter s, Iter e) {
 using std::swap;
 Iter i1, i2;
 ...
 swap(*i1, *i2);
}

だと何か問題あるのか?
0242デフォルトの名無しさんNGNG
>>231
すまん書き間違えた...

×: エラーコードがスレッド毎に保存されることぐらい常識だと思うが...。
○: (マルチスレッドを考慮に入れるなら) エラーコードをスレッド毎に保存することぐらい常識だと思うが...。

まさかやり方知らないとか ?
0243デフォルトの名無しさんNGNG
>>238
リフレクションが使えるC++
0244デフォルトの名無しさんNGNG
> エラーコードをスレッド毎に保存することぐらい

gccだとどうやるの?
0245デフォルトの名無しさんNGNG
threadハンドルをキーにmapする。
0246228NGNG
>>241
それだとmyns::swap()が見えない。
ちなみに単にswap()だけ、あるいはusing namespace stdだと、
*i1,*i2がprimitive型の時にstd::swap()が見えなくなる。
0247デフォルトの名無しさんNGNG
>>242 >>245
だからメンバ変数だっていってんだろ!!
オブジェクト一つずつにそんなことする気か?

>threadハンドルをキーにmapする。
これじゃ足りねーよ
0248デフォルトの名無しさんNGNG
>>244
スレッドは C++ の標準じゃねーから、単に gcc と書かれても困る。
0249デフォルトの名無しさんNGNG
てかスレッドごとにインスタンス作れよ
0250デフォルトの名無しさんNGNG
あるクラスのstaticなメンバ関数で共通に使いたいmutexを初期化したいのです。
Javaだったらスタティックイニシャライザでクラスに属するリソースの初期化処理をやりますよね。
でも、C++では言語としてそのような機能はないみたい(あるのかも知れないが、私は知らない)。
そこで、以下のようにグローバル変数で初期化しているのですけど、

namespace _hoge {
pthread_mutex_t mutex;
class Initializer {
public:
Initializer(){
pthread_mutex_init(&mutex, NULL);
}
};
Initializer initializer;
};

なんかダサい気がします。もっとよい方法を識者の方に伺いたいです。
(ちなみに、mutexをクラスのメンバにしてPTHREAD_MUTEX_INITIALIZERで初期化すると
「インテグラルじゃない値を初期化しようとしてる」みたいな警告が出るのでもっとダサい)
0251デフォルトの名無しさんNGNG
コンストラクタ内で初期化しろ。
二回目以降はスキップ。
ダサいのがいやならカエレ!
0252デフォルトの名無しさんNGNG
>>250
pthread_mutex_t を、initするクラスでラップしといてから

template<class T>
inline CMutex& common_mutex_of() {
 static CMutex mutex;
 return mutex;
}
0253250NGNG
>>251
コンストラクタ内で初期化する方法だと、mutexを初期化するのは、メインスレッド
でやらないと駄目。でもメインスレッドから hoge::init() みたいなのを呼ぶのはダサい(呼び忘れるから)。
で、コンパイル時か、実行時でもmain関数より前に初期化を行いたい。
0254250NGNG
>>252
おお。目から鱗かもです。
0255デフォルトの名無しさんNGNG
チョッと待て、>>252も呼び出す時がいつかで競合の問題がある
ほら

pthread_mutex_t mutex;
bool pinit(){ pthread_mutex_init(&mutex, NULL); return true; }
bool pinitialized=pinit();

これでどうよ?
0256デフォルトの名無しさんNGNG
namespaceっていつから流行ってんの?
それ一般的に使われてんの?

学究的な興味なんざ小指の爪の先ほどもない。
職業プログラマとして必要な技術?
0257デフォルトの名無しさんNGNG
無理しないでnamespaceと対になったinitializerクラスで我慢しとけよ。
0258250NGNG
>>255
あ、それでいいのか。
でもやっぱグローバル変数使わざるを得ない?
staticなメンバ変数と関数だけで済ませられないでしょうか。
(駄目なら、グローバル変数での初期化が定石ってことでいいのでしょうか)

>>256
標準ライブラリで使われている気が、、、
0259デフォルトの名無しさんNGNG
>>258
staticなメンバ変数はほとんどグローバル変数と同じようなもんだぞ?
0260デフォルトの名無しさんNGNG
マジで標準ライブラリに?
うーむ、ぐぐっても解説等出てこないから比較的新しい技術なのかと思っていたが、
C++の標準的な「何か」なのかな・・・
CからC++へ、なんとなく体で移行してきたんでわからんことが大杉。
本腰入れて勉強しないと限界みたい・・・
0261デフォルトの名無しさんNGNG
とあるライブラリの関数foo()と別のライブラリの同名関数foo()を同一ソースでコールしたい。
さてどうする?
0262250NGNG
>>259
確かにそうですね。結局、namespaceで保護するのが関の山ですかね。
0263デフォルトの名無しさんNGNG
>>262
無名ネームスペースに閉じ込めたら?
0264デフォルトの名無しさんNGNG
>>239

正しくない。
意味のある使い方がまだある。
0265250NGNG
>>263
なるほど。っていうか、無名namespaceってのは初めて知りました。
mutex を、それを利用するクラスのメンバにして、
初期化は無名namespaceのグローバル変数を使ってやると。
それが一番かもしれないですね。
0266名無しさんNGNG
ぬるい話題が多いな。
るいじの質問もあるし…
ぽんと,いい考えがうかばないのか?
0267デフォルトの名無しさんNGNG
ぬるくない問題はC++では解決できないからねぇ。
そういう人はとっくにC#に以降済みだし。
0268デフォルトの名無しさんNGNG
ミノガスカヨッ
  ( ・∀・)   | | ガッ
 と    )    | |
   Y /ノ    人
    / )    <  >__Λ∩
  _/し' //. V`Д´)/
 (_フ彡        /  ←>>266
0269デフォルトの名無しさんNGNG
C#だとよ(w
0270デフォルトの名無しさんNGNG
>>228,>>230
ユーザー定義型を使って標準ライブラリのテンプレートを特殊化することは認められている。
17.4.3.1 -1- (ttp://www.kuzbass.ru/docs/isocpp/lib-intro.html#lib.reserved.names)

オーバーロードの追加が認められているという記述は見当たらなかった。
0271228NGNG
>>270
おお!特殊化なら合法だったんだ。
これで幸せになれそうです。ありがとうございます。
0272デフォルトの名無しさんNGNG
>>270
テンプレートライブラリを作成するときにstd::swap(a,b)を使うことを考えると、
自前のswap処理を作ったならstd::swapの特殊化をしておくべきだと思うんだが、
boost::scoped_ptrなんかは、boost::swapが定義されてるな。
これだと、
 scoped_ptr<T> a,b;
 std::swap(a,b);
と書いても、a.swap(b)にはならないな。
0273272NGNG
http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2001/n1296.htm
↑によると、

namespace std
{
 template<typename T>
 class X {};
 template<typename T>
 void swap(X<T>& rhs, X<T> lhs);
}

これは特殊化ではなく、オーバーロードの宣言になるので、規格違反になるそうだ。

結果として、
自前のクラスについてstd::swap等の特殊化はできるが、
自前のクラステンプレートについては(規格に従う限り)不可能らしい。
0274デフォルトの名無しさんNGNG
クラステンプレートが static なデータメンバを持っているとき、複数のコンパイル単位で、
その static なデータメンバの定義を行っても、リンク時に一つにまとめられてしまうよう
なのですが、これは規格に則った動作でしょうか。

-- X.h --
template<class T> class X {
static T x;
};
template<class T> T X<T>::x;

-- Foo.cpp --
#include "X.h"

void foo()
{
X<int> a;
}

-- Hoge.cpp --
#include "X.h"

void hoge()
{
X<int> b;
}

ここで Foo.cpp と Hoge.cpp をコンパイルしてリンクしても、とくに X<int>::x の
多重定義にはならず、正常にリンクされます。(g++ と VC++ で確認)

しかし、C++第3版の 13章7節によると「非inline の static メンバは、どこかの翻訳単位に
ユニークな定義を持たなければならない。」とあり、上のような動作は保証されていない
ようなのです。
0275デフォルトの名無しさんNGNG
>>274
14.5.1.3にX.hの内容と同じ例があげられている。
その挙動を疑うなら、以下のソースも疑うことになると思うのだが・・・。

-- X.h --
template<class T>
void f();

-- Foo.cpp --
#include "X.h"

void foo()
{
f<int>();
}

-- Hoge.cpp --
#include "X.h"

void hoge()
{
f<int>();
}

0276275NGNG
あ、ごめん。訂正。

-- X.h --
template<class T>
void f(){}

0277デフォルトの名無しさんNGNG
? これ同じ例か?
0278デフォルトの名無しさんNGNG
?HogeHoge@@YAHG@Z
を元に戻すテーブルかなにかはありませんか?
0279デフォルトの名無しさんNGNG
>>278
WinならUnDecorateSymbolNameというのがある
0280デフォルトの名無しさんNGNG
undname -f ?HogeHoge@@YAHG@Z

?HogeHoge@@YAHG@Z == int __cdecl HogeHoge(unsigned short)
0281278NGNG
Σ(*゚Д`;)ア…ア…アッハァァァァァァァァ?!!
すばらしいですぞ、このような時間に!!!
はげしくあげしく、感謝します。
0282デフォルトの名無しさんNGNG
以下のように、相互にincludeしたいのですが、エラーが出てしまいます(´Д⊂
こういう場合は、2つのクラスを、同じヘッダにまとめるしか無いのでしょうか?

----------------A.h
#ifndef A_H
#define A_H

#include "B.h"

class A(){
A( B* b );
};

#endif
----------------B.h
#ifndef B_H
#define B_H

#include "A.h"

class B(){
B( A* a );
};

#endif
----------------
0283デフォルトの名無しさんNGNG
----------------A.h
#ifndef A_H
#define A_H

#include "B.h"

class B;
class A(){
A( B* b );
};

#endif
----------------B.h
#ifndef B_H
#define B_H

#include "A.h"

class A;
class B(){
B( A* a );
};

#endif
----------------
0284282NGNG
>>283
見事にリンクできました。これがクラスの前方参照…。
助かりました。ありがとうございました。
0285デフォルトの名無しさんNGNG
初歩的質問です。

int x=0;

int *a = &++x; // OK
int *b = &x++; // エラー

bの初期化でエラーになるのはなぜでしょうか?
コンパイラによれば'&'に左辺値がないとのことですが・・・。
自分のイメージとしてはxのアドレスでbを初期化した後、
xをインクリメントするという感じなのですが・・・。
0286デフォルトの名無しさんNGNG
&(x++)
0287デフォルトの名無しさんNGNG
>>286
エラーですよ
0288デフォルトの名無しさんNGNG
優先順かな。
下は&xが評価された後にインクリメントされるから、
一時領域のインクリメントはできないのか、あいまいさではじかれてるのかどっちかでしょう。
エラーコードを見ればどっちかわかる。
0289285NGNG
ちなみに私が知りたいのは、どうしたら自分のイメージどうりに
動かせるかではなく、なぜエラーになるのかです。
結合順位からいえば、もともとインクリメント演算子の方が強いのですが・・。
0290デフォルトの名無しさんNGNG
禿本の p161 に説明があるけどピンとこないな。

>論理的に可能であれば、左辺値の被演算子を取る演算子の処理結果は、
>その左辺値被演算子を示す左辺値になる。
 (略)
>int *p = &++x;  // p は x を指す
>int *q = &(x++); // エラー: x++は左辺値(xに格納されている値)ではない

x に副作用が発生するタイミングは前置でも後置でも ; に至るまでの
いつかでしかないと思うのだけど前置のみ左辺値になるのはどうして
だろう。
0291デフォルトの名無しさんNGNG
>>289
まあ ++x は、極論すれば、{x = x + 1, x} と同じだからアドレスがとれる。
でも、x++ は、{(x = x + 1)} と言う式になるから、アドレスが取れない。
0292デフォルトの名無しさんNGNG
だから、前置は式評価前にインクリメント、後置は式評価後にインクリメントするからだろ?
0293285NGNG
本の解説でも、コンパイラのエラーメッセジでも
あくまで&に対する左辺値が無いということが原因みたいですね。

ちなみに

int *r = &(x += 1); // OK

これはOKでした。これが前置と同じことなんですかね・・・。
後置だとカッコの中身が先に評価されないとか(超適当)。
0294デフォルトの名無しさんNGNG
式ってのはxね。
0295デフォルトの名無しさんNGNG
>>292
前置の場合 x の副作用が式の評価前に行われるのは保証されてるの?
0296デフォルトの名無しさんNGNG
int a, b, c;
a = 0;
b = a++;
c = ++a;

bは0、aは1になるのはわかってんだよね?
0297デフォルトの名無しさんNGNG
× bは0、aは1
○ bは0、cは1
0298デフォルトの名無しさんNGNG
あーちがう!
このままじゃcは2になるやん。
まぁ雰囲気だけ味わってくれ・・鬱だ死のう。
0299デフォルトの名無しさんNGNG
cは2じゃないか?
0300デフォルトの名無しさんNGNG
int& operator++(int&);
int  operator++(int&,int);

int  x = 0;
int* a = &(operator++(x));
int* b = &(operator++(x,0));
0301デフォルトの名無しさんNGNG
T& operator++(void) { m_nakami+=1; return *this; }
T operator++(int) { T temp=m_nakami; m_nakami+=1; return temp; }

後者の返り値は値(一時変数だから参照を返せない)だから
アドレスがとれないってことじゃなくて?
0302デフォルトの名無しさんNGNG
基本型でない型の振る舞いと対称性を保つためにエラーにせざるを
得ないということ? template とか。本末転倒な気もするけども。
0303デフォルトの名無しさんNGNG
はぁ?
0304デフォルトの名無しさんNGNG
Cではどっちもエラーになるな。
0305デフォルトの名無しさんNGNG
> int* b = &x++;
↑こんなコード、コンパイルできるようにしてもなんのメリットもないだろ。
0306302NGNG
>>303
>>300-301 が言ってるのはそういうことじゃないのか?
0307デフォルトの名無しさんNGNG
>>305
だからなんなんだ?

勉強のできないやつってのは、なぜそうなるか?どういう原理なのか?
といったことにはまったく興味をしめさず、できればいい、動けばいい
的な考えなんだよな。だから応用もきかないし、所詮そこ止まりの人間。
そういう奴はベーシックでもやってりゃいい。
0308300NGNG
>>306
オーバーロード可能な演算子のシグネチャとして、
C++では演算子'++'を>>300のように定義した。
この定義には「基本型でない型の振る舞いと対称性を保つ」目的があったかもしれない。
その結果、Cではコンパイルできなかった式'&++x'はコンパイル可能になった。
ここは「コンパイル可能にせざるを得ない」という話になるだろう。

だが、'&x++'「エラーにせざるを得ない」なんて話には、どうにもつながらない。

ちなみに、300==305。
>>307
何のメリットも無いのに、Cと異なる挙動とする意味でもあるのか?
0309デフォルトの名無しさんNGNG
>>306
もし>>302の疑問が正しいのであればそもそもC言語でも駄目なのはどうしてだ?
C言語では基本型以外にoperator ++は定義できない
0310デフォルトの名無しさんNGNG
>>何のメリットも無いのに、Cと異なる挙動とする意味でもあるのか?

そういうこと言っているわけじゃねぇだろって
もっと一般的な話だろ(プログラムに限らずな)
0311306NGNG
>>300
Cと比較すると解釈が逆になることが分かるな。
でもメリットて話だとしたら、&++x にどんなメリットがあったのか
疑問だ。Cと同じように左辺値になり得ないとしたら問題が起こる
のだろうか。
0312デフォルトの名無しさんNGNG
>&++x にどんなメリットがあったのか疑問だ。

意味がわかりません!!メリットなんて別にないだろ!!
0313306NGNG
>>312
メリットが無いのであれb &++x も C と同じように左辺値に
ならなければよかったんでは。
0314306NGNG
>&++x も
++x も
0315デフォルトの名無しさんNGNG
VC++って標準C++とは限らないんだな・・・。
for(int i = 0; ... ; ...)
このiのスコープもデフォルトではforブロック外だよな、.netは。
ほかにも、標準C++に沿ったコーディングでエラーにもなるし。
標準C++のコンパイラってあんの?
0316デフォルトの名無しさんNGNG
ストラップにメールだしてくれ。
0317300NGNG
>>306
> &++x も C と同じように左辺値にならなければよかったんでは
左辺値にならないとしたらオーバーロード可能なシグネチャの定義が、
 int operator++(int&)
というようなものになり、
ユーザー定義型で効率のよい実装が難しくなる。

>>310
あれ?外してた?あんた>>307か?
何を突っ込まれたのかわからない。ごめん。
0318デフォルトの名無しさんNGNG
&++x ←これって左辺値じゃないよね?
++x ←これは左辺値になるけど
x++ ←これは左辺値じゃない
0319デフォルトの名無しさんNGNG
まあ、確かに++xを左辺値にする必要はないのかな?
0320デフォルトの名無しさんNGNG
(++x)=10;
とかできてもうれしくないしな・・・
0321デフォルトの名無しさんNGNG
メリットうんぬんじゃなくて、結合やらなにやらの思想の統一性から
こうしたのかもしれないね・・・。なにを基準に決めたのか知らんけど。
0322デフォルトの名無しさんNGNG
でも ++x = ++y とか書きたいときがある。ない?
今議論されてることって一貫性の問題?
0323322NGNG
激しくかぶった。ごめ。
0324デフォルトの名無しさんNGNG
しかしK&Rにせよストラウストラップにせよ、わざわざ
読者をなやますようなコードをちりばめるね・・・。
参考書というよりは教科書チックだな。
0325デフォルトの名無しさんNGNG
C++では (x = y) = z; がエラーにならずに通るからね。Cでは見事に
エラー。
0326デフォルトの名無しさんNGNG
>>322
*++x = *++y;
こうじゃないの?
++x = y++
は何が起こるの?
0327デフォルトの名無しさんNGNG
++x = ???
ってけっきょく???で上書きされるから
インクリメントを事前にしても意味ないんじゃ・・・。
0328306NGNG
効率の問題で ++x が左辺値になることを許してしまうというのも
なんだかな・・・。
0329デフォルトの名無しさんNGNG
別に効率の問題ではない。
勘違いしているだけでしょう。
0330デフォルトの名無しさんNGNG
int x = 0;
int y = 5;

++x = y++;

cout << x << endl;
cout << y << endl;

result:
5
6
0331デフォルトの名無しさんNGNG
はあ
++xは意味がないですね
■ このスレッドは過去ログ倉庫に格納されています