C++相談室 part58 ..
[2ch|▼Menu]
97:91
07/09/30 20:59:12
>>95
部分特殊化はOKだったんですか。気づきませんでした。
早速試してみます。どうもありがとう〜!!


98:デフォルトの名無しさん
07/09/30 21:00:46
>>91
私はC++初心者ですが、>>93さんと同意見です。
>>95さんの言うようにgccの方が正しい(つまり規格どおりということですよね)ならば、
なおさらそう思います。

それに、Xクラスの定義を見たいときには、むしろYは外にあった方が見やすいのではないでしょうか?

99:デフォルトの名無しさん
07/09/30 21:06:58
ちなみに関数テンプレでもこの手は使えるようだ
この手法も名前があったと思うけど思い出せない
使うなら適当にローカルなメタ関数を専用の名前空間に自作して階層を浅くする工夫が必要だね
使ってればわかるけど、凄く見にくくなるから


100:デフォルトの名無しさん
07/09/30 21:10:12
あ、::type付けわすれた…

101:デフォルトの名無しさん
07/09/30 21:43:54
読み易くするのが目的で読みにくくなる手法を選ぶか。
>>99 名前があるならソレをコメントに書いておけば良いかも。

102:デフォルトの名無しさん
07/09/30 22:00:44
>>98 >>101
読みやすいかどうかは読み手にもよるし、あまり>>91>>94はよい聞きかたではなかったですね。
C++のコードを自動生成するツール(自作)の都合でX内に定義を書けると嬉しい、というのが実際の事情です。


103:91
07/09/30 22:32:03
102は91です。

>>99
concept-controlled polymorphism ですか?


104:デフォルトの名無しさん
07/09/30 23:06:47
>>100
> あ、::type付けわすれた…
検索エンジン経由で来るひとのために、一応訂正版貼っときますね。

#include <cstdio>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_same.hpp>

struct X {
  template<typename T, typename U = void> struct Y {
    Y() { std::printf("genecic\n"); }
  };
  template<typename T> struct Y <T, typename boost::enable_if<boost::is_same<T, int> >::type> {
    Y() { std::printf("specialized for int\n"); }
  };
};
class Z {};

int main() {
  X::Y<Z> a;
  X::Y<int> b;
  X::Y<float> c;
}

実行結果は、
genecic
specialized for int
genecic
です。


105:91=104
07/09/30 23:31:30
boostが使えない場合は、VC++2003/2005/g++対応だけ考えるならこんな感じでしょうか。
#include <cstdio>
namespace b00st {
  template <bool B, class T = void>
  struct enable_if_c {
    typedef T type;
  };
  template <class T>
  struct enable_if_c<false, T> { /* NO TYPEDEF! */ };
  template <class Cond, class T = void>
  struct enable_if : public enable_if_c<Cond::value, T> {};
  template<bool b> struct bool_ {
    static const bool value = b;
  };
  template<typename T, typename U>
  struct is_same : bool_<false> {};
  template<typename T>
  struct is_same<T, T> : bool_<true> {};
}
using namespace b00st;
struct X {
  template<typename T, typename U = void> struct Y {
    Y() { std::printf("genecic\n"); }
  };
  template<typename T> struct Y<T, typename enable_if<is_same<T, int> >::type> {
    Y() { std::printf("specialized for int\n"); }
  };
};
そろそろウザいとおもうので、これで打ち止めにします。ありがとうございました。


106:デフォルトの名無しさん
07/09/30 23:40:10
このtemplate感、実に小気味良い 久しぶりにC++スレを実感した

107:デフォルトの名無しさん
07/10/01 00:01:02
キモ

108:デフォルトの名無しさん
07/10/01 00:04:13
小気味良いのは確かだけど、言葉遣いが丁寧すぎてちょっと痒い、というのが俺の感想。
うん、俺の感想なんかどーだっていいってのは承知。

109:デフォルトの名無しさん
07/10/01 02:02:08
>>99
enable_ifの関数テンプレへの適用で質問。ある条件で2つの関数を呼びわけたいときは、こんな感じにすればいいみたいだけど、
  template<typename T>
  static void foo(T t, typename boost::disable_if<boost::is_same<T,int> >::type* = 0) {
  }
  template<typename T>
  static void foo(T t, typename boost::enable_if<boost::is_same<T,int> >::type* = 0) {
      // intへの特殊化版
  }
3つ以上を呼びわけるにはどうすれば? たとえば、
  template<int V>
  static void boo(typename boost::enable_if_c<V == 0>::type* = 0) { }
  template<int V>
  static void boo(typename boost::enable_if_c<V == 1>::type* = 0) { }
  template<int V>
  static void boo(typename boost::disable_if_c<V == 0 || V == 1>::type* = 0) {
     // default
  }
とかだと、default caseな関数の引数が大変なことになってしまうような。
boostスレのほうがいいのかな。。

110:デフォルトの名無しさん
07/10/01 02:51:44
複雑な場合はmplの出番になるんじゃないかな

mpl::if_< ...,
mpl::if_< ...,

> >::type::call();


111:109
07/10/01 03:23:49
>>110
すみません、それはどこに書くコードなんでしょうか?
call() とは一体。。



112:109
07/10/01 03:28:24
>>110が理解できず、独自に考察を進め中。
  template<int V>
  static void boo(typename boost::enable_if_c<V == 0>::type* = 0) {}
は、
  template<int V>
  static void boo(typename boost::enable_if<
                    boost::is_same<
                      boost::mpl::int_<V>,
                      boost::mpl::int_<0>
                    >
                  >::type* = 0) {}
であり、さらに
  template<int V>
  static void boo(typename boost::enable_if<
                    typename boost::mpl::lambda<
                      boost::is_same<
                        boost::mpl::_1,
                        boost::mpl::int_<0>
                      >
                    >::type::apply<boost::mpl::int_<V> >::type
                  >::type* = 0) {}
だから、この数値0-Nでlambdaしたのをmpl::listで抱えて、特殊化版はlistのat<i>したのでenable_ifして、default版はこれらをandでfoldしたのにdisable_ifすればいいと思うんだぜ?

・・・絶対方向が間違ってる。

113:デフォルトの名無しさん
07/10/01 03:37:53
いや、単に、mpl::if_で関数を実装したクラスを選んで呼び出す
boost/smart_cast.hppが参考になるかも

114:デフォルトの名無しさん
07/10/01 03:44:43
>>113
私は、単に boo(0); boo(1); boo(2); とだけ書くと、呼び先の関数がコンパイル時に決まるようにしたいと
思っているんですが、>>110は、このbooを *呼ぶ側* をif_で工夫しろということ?

まぁ、boo()でif_を使って、適切なboo_()を呼ぶようにしてもいいのかもしれませんが、
委譲してしまうとタグディスパッチと大差ないようにも思うし。。

なんか勘違いしてたらすんません。smart_castは早速見てみます。

115:デフォルトの名無しさん
07/10/01 04:37:09
どうしてもenable_ifを使いたいなら
複雑な条件を書かずに済ますことは不可能だと思う

116:109
07/10/01 05:41:56
>>115
enable_ifが使いたいわけでは無くて、

1.メンバ関数テンプレートの特殊化(相当のこと - オーバーロードでもいい)を行いたい
2.特殊化の定義は、クラス内に書きたい (>>91と同じく, 見た目の問題で)
3.メンバ関数を呼ぶ側はあまり難しいことを考えたくない
4.タグディスパッチのような別関数への処理の委譲は、できれば避けたい (これも見た目の問題で)

という条件で、Pという場合と!Pという場合の処理の振り分けだったら、
enable_ifを使ったオーバーロードでOKとわかった(>>109)が、P, Q, (!P && !Q)
の3関数に振り分けたい場合にこの4条件を満たすようなのないですかね?

というのが質問です。ちゃんと書かずにすみません。コンパイラはgccです。



117:デフォルトの名無しさん
07/10/01 05:47:44
>この4条件を満たすようなのないですかね

自分で書いた>>109が満たしてると思うんだが

118:デフォルトの名無しさん
07/10/01 05:58:35
>>117
おっしゃる通りなんですが、>>109は、V==0やV==1という条件が
繰り返し登場してしまい、メンテナンス性がいまいちかなと思いまして。
実際はenumとか扱いたいので。

109の繰り返しになりますけど、条件1-4をみたし、かつdefault case

template<int V>
static void boo(typename boost::disable_if_c<V == 0 || V == 1>::type* = 0) {   /* default */ }

を綺麗にかけないですかね。

template<int V> static void boo(...) { /* default */ }

とかが通れば最高なのに。

119:デフォルトの名無しさん
07/10/01 06:02:23
struct a_condition : mpl::bool_<...> {};
としてenable_ifに渡すとか

120:デフォルトの名無しさん
07/10/01 09:08:09
kwsk

121:デフォルトの名無しさん
07/10/01 09:54:53
引数忘れた
こんな感じ
enable_if< my_conditionA<V> >

まあディスパッチすべきだな
enable_ifはこの場合必要ないから

122:デフォルトの名無しさん
07/10/01 11:56:27
デザパタのプロトタイプパターンを使ってみたいのですが
ばらばらに clone() 関数をとりつけるよりも
ひとつ Clonable クラスを作って、そのクラスから
継承したほうがよいでしょうか?

123:デフォルトの名無しさん
07/10/01 12:34:46
そういう継承ってどうなんだろうね。

124:デフォルトの名無しさん
07/10/01 17:41:51
noncopyableとかあるし、いいんじゃね?

125:デフォルトの名無しさん
07/10/01 18:16:10
traitsを作れば継承はいらないと思うよ

126:デフォルトの名無しさん
07/10/02 21:42:40
#include <boost/numeric/ublas/vector.hpp>
using namespace boost::numeric::ublas::inner_prod;

VC++2005EEの環境でビルドすると、
error C2867: 'boost::numeric::ublas::inner_prod' : は名前空間ではありません。
というエラーが出ます。
エラーの原因は何ですか?

127:デフォルトの名無しさん
07/10/02 22:08:58
名前空間ではないものをusing namespaceしたこと

128:126
07/10/02 23:00:22
>>127
URLリンク(sealsoft.jp) このサイトの
> usingを使って、ある識別子をグローバルな名前空間に持ち上げることができる。こうするとその後は大域解決演算子を使う必要がない。
> using namespace seal::foo;
> // 関数fooを呼び出す
> int a = foo();

ここ見てできると思ったんですけど、このサイト間違ってますか?

129:デフォルトの名無しさん
07/10/02 23:27:47
usingディレクティブ (using namespace)の対象にできるのは、名前空間だけ。
代わりといってはアレだが、その他の識別子一般には、using宣言が使える。
using boost::numeric::ublas::inner_prod;

130:126
07/10/02 23:49:25
>> 129
なるほど、そうなんですか。

URLリンク(msdn2.microsoft.com)(vs.80).aspx
ここを勘違いして見てました。(classの中のusingとは別物なんですね)

クラスの中でnamespace内の関数をusingしたい場合、
class A {
using boost::numeric::ublas::inner_prod;
};
エラーになってしまうのですが、クラス中でnamespace内の関数をusingするのは無理ということですか?

131:デフォルトの名無しさん
07/10/03 00:09:31
そういうこと。クラス定義内のusingは基底クラスの名前を指定することに特化している。
なお、型名だけはtypedefで代用できる。

132:126
07/10/03 00:14:05
ありがとうございました。

133:デフォルトの名無しさん
07/10/03 01:54:49
マクロ使って、行数と引数を連結させたいのですが、

#define macro( name )\
const char *x = "name##__LINE__";

とかやってもできません。
こんなことは可能ですか?

134:デフォルトの名無しさん
07/10/03 02:05:02
__LINE__は定数だからダブルクォーテーションで囲っちゃだめっしょ
で、定数を文字列にするのは単純なマクロじゃ厳しいと思うけど・・・
おとなしく関数にしたほうがよさそう


135:デフォルトの名無しさん
07/10/03 02:07:38
一応マクロでこんな感じでいかが?
#define macro( buf, name ) sprintf( buf, "%s%d", "name", __LINE__);

136:デフォルトの名無しさん
07/10/03 02:10:53
#define NUM2TEXT_(n)    #n
#define NUM2TEXT(n) NUM2TEXT_(n)

#define macro(name) \
const char *x = name ## NUM2TEXT(__LINE__)


137:デフォルトの名無しさん
07/10/03 02:43:41
演算子オーバーロードって副作用完了点のことも考慮しないといけないんですか?
std::cout << "test" << std::endl;
で (a) "test" << std::endl; が先に評価されて、次に std::cout << (a) が評価される、という事態にはならないんですか?

138:デフォルトの名無しさん
07/10/03 03:26:56
優先順位の同じ演算子の並びは左から評価じゃなかったのか

139:デフォルトの名無しさん
07/10/03 04:07:20
左結合と右結合があってね・・・

140:133
07/10/03 05:13:05
ありがとうございます。
>>136さんのは
どういう原理なんでしょうか?

141:デフォルトの名無しさん
07/10/03 08:46:05
7**7**7 の下一桁の数字は?

142:デフォルトの名無しさん
07/10/03 09:44:47
>>137
多重定義されている場合、通常の関数と同様、
呼出の直前に副作用完了点が現れるので心配は要らない。

<<は左結合だから、まずstd::cout << "test"から取り掛かる。
これは多重定義されているので、std::cout.operator <<("test")という関数呼出に相当。
関数呼出の直前には副作用完了点が来るので、ここまでにstd::coutと"test"が評価される。
と言っても、共に副作用を持たないので何も起きないが。
仮に副作用を持つ式だった場合、通常の関数呼出同様に
<<の左側と右側のどっちのオペランドが先に評価されるかは決まっていない。

std::cout.operator <<("test")の戻り値をrとすると、
次にr << std::endlの評価に掛かる。以下同じ。

143:デフォルトの名無しさん
07/10/03 11:51:51
>>140
> 16.3.2 The # operator
> 16.3.3 The ## operator

144:デフォルトの名無しさん
07/10/03 13:50:35
>>133
#define XY(X,Y) X##Y
#define MAKENAMEXY(FX,LINE) XY(FX,LINE)
#define MAKENAME(FX) MAKENAMEXY(FX,__LINE__)
というマクロで連結させている例がある。
評価順その他の関係で、間に一段置かないとならないらしい。

145:デフォルトの名無しさん
07/10/04 00:31:45
VS2008EEで>>136が正常に動作しないんだけど・・・
コンパイラの仕様かな?

146:デフォルトの名無しさん
07/10/04 00:36:58
プリプロセッサの仕様じゃね?とかつまんない事言うね。義務として。

147:デフォルトの名無しさん
07/10/04 00:45:12
すみません。継承について質問です。

クラスBaseを基底とするクラスDerivAやクラスDerivBがあるとして、
そこからインスタンスを作成するとすると、

Base* pA = new DerivA;
Base* pB = new DerivB;

となると思います。
そこから、pAもしくはpBから新たなインスタンスpCを作りたいと思っているのですが、
どうしたらいいでしょうか?

単にpA(DerivA)だけであれば、DerivA *pC=*pAだけでいけるのですが、
pAとpB(最終的にはBaseを基底とするクラス全部)にも対応できるものを作りたいので、
どうか力をお貸しください。


148:デフォルトの名無しさん
07/10/04 00:53:05
class Base {
public: virtual Base *NewInstance() = 0;
};
class DerivA : public Base {
public: virtual Base *NewInstance(){ return new DerivA; }
};
class DerivB : public Base {
public: virtual Base *NewInstance(){ return new DerivB; }
};

Base *pA = new DerivA;
Base *pB = new DerivB;
Base *pC = pA->NewInstance();
Base *pD = pB->NewInstance();

149:デフォルトの名無しさん
07/10/04 00:53:41
Base* pA = new DerivA();
Base* pB = new DerivB();

150:147
07/10/04 01:02:02
>>148、149
目からウロコが落ちました。

インスタンスを作成する関数を別途で作ればいいわけですね。
ありがとうございます。

151:デフォルトの名無しさん
07/10/04 01:04:17
>>148
DerivA::NewInstanceはDerivA*を返し、
DerivB::NewInstanceはDerivB*を返し、
という具合に、そこは共変にしてほしいな。

152:デフォルトの名無しさん
07/10/04 01:06:08
凶変を許したことでできるようになったことってなんだっけ?
なんかの本にかいてあったが忘れた


153:デフォルトの名無しさん
07/10/04 01:15:57
>>136
boostにはなんて名前で入ってたっけ

154:デフォルトの名無しさん
07/10/04 01:18:23
>>152
pAはDerivA*と分かっているとき、
DerivA* pA2 = static_cast<DerivA*>(pA->NewInstance());
のようなキャストを型安全性を損なうことなく排除できる。

155:デフォルトの名無しさん
07/10/04 02:07:15
dynamic_castすれば共変なしでも安全じゃね?

156:デフォルトの名無しさん
07/10/04 02:08:25
URLリンク(videointroplayer.web.fc2.com)

157:デフォルトの名無しさん
07/10/04 02:29:39
>153
BOOST_PP_STRINGIZE

158:デフォルトの名無しさん
07/10/04 08:19:17
これじゃだめなん?

Base *pC = new DerivC;

159:デフォルトの名無しさん
07/10/04 08:20:10
Base *pC = new DerivC(pA);
Base *pC = new DerivC(pB);


160:デフォルトの名無しさん
07/10/04 21:28:42
>>155
それだと余計な負荷がかかる。

161:デフォルトの名無しさん
07/10/05 01:29:04
俺的c++開発環境構築メモ

目的:最終的にlinuxで動かせるようにしないといけないけどVisual Studio捨てれない

winxpにvmwareいれてゲストOSとしてubuntu7を入れる
ubuntuの/home/srcをsambaで共有できるようにしてホストOSのwinxpからみれるようにする

/home/src = \\ubuntu\src
の下にVisual Studioのプロジェクト作成

makefileはeclipse/CDTで自動生成

あとはemacsでメインのコードの編集するけど、flymakeとか使いつつ
インテリセンスも使えてeclipse/cdtのリファクタリング機能も使える環境のできあがり

162:デフォルトの名無しさん
07/10/05 04:20:16
俺がいる

163:デフォルトの名無しさん
07/10/05 08:18:16
もう遅いだろうがcoLinuxを薦めてみる

164:デフォルトの名無しさん
07/10/05 12:27:41
coMomongaを勧めてみる


165:デフォルトの名無しさん
07/10/05 12:59:49
coLinuxの方が便利なの?
速度が速い以外のメリットがないなら、もう乗り換えれない

166:デフォルトの名無しさん
07/10/05 15:23:45
coLinuxってkernelのバージョンあがるたびに中身を全消ししないといけないって聞いたのだけど
違うの?

167:デフォルトの名無しさん
07/10/05 17:36:55
ヘッダファイルなどで記述したグローバルなstatic変数は,
includeしたソースが複数ある(各ソースではincludeガードが起きずに展開される)
場合も単一の存在となるんでしょうか?
それとも別々の独立した変数となるんでしょうか?

168:デフォルトの名無しさん
07/10/05 17:41:00
それをインクルードしたソースファイルごとに別々に作られることになる

169:デフォルトの名無しさん
07/10/05 18:02:52
ありがとうございます.
あれ,でもクラス変数などは単一なんですよね?
うーむ,基本の理解が全然出来ていない.

170:デフォルトの名無しさん
07/10/05 18:26:17
クラスの static 変数はどこかで1個だけ実体を定義する必要がある。

class A{
 static int x;
};
int A::x;  // <-- これ

2個以上のソースファイルで定義したら、定義が重複してるってリンクエラーになる。
static でない普通のグローバル変数と同じあつかい。

171:デフォルトの名無しさん
07/10/05 20:36:51
#includeは単にファイルをくっつけてるものと考えれば理解しやすいかも


最新レス表示
スレッドの検索
類似スレ一覧
話題のニュース
おまかせリスト
▼オプションを表示
暇つぶし2ch

5370日前に更新/51 KB
担当:undef