> Container& operator+(const Container& line) const
> {
> static Container temp;
将来ハマる可能性(並列実行したりとか)も考えると、
汎用的に作るなら素直に実体を返した方がよくないですか。
> 「'_'で開始する識別子はコンパイラが予約語として使用できる」ので非推奨だった
> と思ったけど、今、調べたら「'_'二つで始まる、または'_'に続いて大文字で始ま
る」
> ってのしか見つからない。本当の所はどうなんでしょうね。
「本当の所」が知りたいなら規格にあたればいいやん。
C++ working draft N3090 によると:
17.6.3.3.2 Global names [global.names]
1 Certain sets of names and function signatures are always reserved to the
implementation:
— Each name that contains a double underscore _ _ or begins with an
underscore followed by an uppercase
letter (2.12) is reserved to the implementation for any use.
— Each name that begins with an underscore is reserved to the implementation
for use as a name in the
global namespace.
なので '_'から始まる名前は予約されてて、僕らが使っちゃダメ。
> Container& operator+(const Container& line) const
> {
> static Container temp;
> ...
> return temp;
> }
...ダメダメじゃねぇの?
> なので '_'から始まる名前は予約されてて、僕らが使っちゃダメ。
> Each name that begins with an underscore is reserved to the implementation
> for use as a name in the global namespace.
ご自身でも引用されているように、__ならばany useなのでご指摘どおりですが、
_で始まって大文字が続かない名前は *グローバルネームスペース内で*
予約されてるだけですから(ISO/IEC 14882:2003でも一緒です)、
それ以外についてはmaruさんの発言が正しいかと思いますが…。
# 但し、環境依存のヘッダやらがマクロ定義とかしてる可能性があったりするわけで、
# 使わない方が安全だとは思います。
すみません、誤読してましたので訂正です。
> 「'_'二つで始まる、または'_'に続いて大文字で始まる」
アンダスコア二つの時は アンダスコア二つで始まる必要はない
(途中や最後にあっても予約される)ので、正しいと言い切れませんでした。
> _で始まって大文字が続かない名前は *グローバルネームスペース内で*
> 予約されてるだけですから(ISO/IEC 14882:2003でも一緒です)、
> それ以外についてはmaruさんの発言が正しいかと思いますが…。
ええ。とはいえ'わざわざ'使う合理的な理由はなさげっすねー。
hirocco さんお世話になります、ツッコミを入れるほどの器量はありませんが
他の方が書かれていた、初期化子リストによる、コンストラクタの初期化程度しか、
気づきませんでした。ことεπιστημη 氏による
> Container& operator+(const Container& line) const
> {
> static Container temp;
> ...
> return temp;
> }
この部分ですが、なぜだめなのかさえ、理解できません・・・・
さて。
掲示して頂いた、コードですが、どストレートで、コンストラクタに数値と、
文字列 を持たせるというアイデアでユニークだと思います、勉強になります。
私は、templateクラスを用いて文字列、数値のキャストを実装してみました
肝のlexical_cast クラスは、επιστημη 氏の「C++テンプレートテクニック」
からの引用となります。
// lexical_cast.h
#pragma once
#include <sstream>
#include <boost/lexical_cast.hpp>
template <class To, class From>
To lexical_cast(From from)
{
To result;
std::stringstream ss;
ss << from;
ss >> result;
return result;
}
template <class From>
class lexical_cast_t {
From from_;
public:
lexical_cast_t (From from)
:from_(from){}
template <class To>
operator To() const
{
return lexical_cast<To>(from_);
}
};
template <class From>
lexical_cast_t<From> lexical(From from)
{
return lexical_cast_t<From>(from);
}
// Container.h
#pragma once
#include stdafx.h
#include <fstream>
#include <string>
template <typename T, size_t N=8>
class Container
{
public:
T m[N];
Container<T> operator+(const Container<T>& rhs) const
{
Container tmp;
for(int i=0; i<N; ++i)
tmp.m[i] = tmp.m[i] + rhs.m[i];
return *this;
}
Container<T> operator=(const Container<T>& rhs) const
{
Container tmp;
for(int i=0; i<N; ++i)
tmp.m[i] = rhs.m[i];
return *this;
}
Container(void){}
~Container(void){}
};
// Container.cpp
#include <iostream>
#include Container.h
#include lexical_cast.h
using namespace std;
int main(void)
{
Container<string> container;
const int DATA_MAX = 8;
char buffer[20];
//文字列データをコンテナいれる
for(int i = 0; i < DATA_MAX; ++i)
{
sprintf(buffer,0.%1.1x,i);
container.m[i] = buffer;
}
// コンテナクラスで+ 演算を行うと、予想通り単なる文字列の結合が行われ
る。
container.m[0] = ";
container.m[0] = container.m[1] + container.m[2];
cout << 0.1+0.2 文字列結合処理結果 << endl;
cout << container.m[0] << endl;
// そこでlexical クラスを使い、std::string → doubleの変換を行う。
double dlhs = lexical(container.m[1]);
double drhs = lexical(container.m[2]);
double result = dlhs + drhs;
cout << 0.1+0.2 数値演算処理結果 << endl;
cout << result << endl;
return 0;
}
>> Container& operator+(const Container& line) const
>> {
>> static Container temp;
>> ...
>> return temp;
>> }
> この部分ですが、なぜだめなのかさえ、理解できません・・・・
struct hoge {
int val;
hoge(int v) : val(v) {}
hoge(const hoge& h) : val(h.val) {}
hoge& operator+(const hoge& h) {
static hoge result(0);
result.val = val + h.val;
return result;
}
};
#include <iostream>
int main() {
hoge one(1), two(2), three(3);
hoge& five = two + three;
hoge six = one + five;
std::cout << five.val << std::endl; // こいつまで6になる
std::cout << six.val << std::endl;
}
あるいはマルチスレッド環境だとリエントラントじゃないのでイッパツでコケます。
> Container<T> operator+(const Container<T>& rhs) const
> {
> Container tmp;
> for(int i=0; i<N; ++i)
> tmp.m[i] = tmp.m[i] + rhs.m[i];
> return *this;
> }
>
> Container<T> operator=(const Container<T>& rhs) const
> {
> Container tmp;
> for(int i=0; i<N; ++i)
> tmp.m[i] = rhs.m[i];
> return *this;
> }
tmpの結果が使われていないようですが…。
> 「本当の所」が知りたいなら規格にあたればいいやん。
そりゃそうなんですが、その規格を探せていないもんで。orz
standardってdraftの段階では公開されているんだけど、制定されるとお金を出して
購入しないと手に入らないものが多くて。まあ、著作権の問題から何だろうけど。
と、言い訳を言ってみる。
>> 「本当の所」が知りたいなら規格にあたればいいやん。
> そりゃそうなんですが、その規格を探せていないもんで。orz
Working draft N3090
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3090.pdf
> CString* _data;
> int _size;
自力でnew[]/delete[]するならメンバにstd::vector<CString>でも
大差ないように思いますし、その方がすっきりするのでは。
…とか考え出すとtypedef std::vector<std::string>でも大差ないか、となって、
そもそもクラスは必要ですか、というところに至りそうですが。
> ということは、クラスにすること自体が冗長かな?www
元コードにしても、一行=8の実装が switch(num % DATA_MAX)でよいくらいの制限で、
非常に大きなデータ数を扱うなど固定サイズ化によるの性能改善を意識しないならば、
一番素直なのはstd::vector<std::vector<std::string> >にでも
(せいぜいreserve程度で)全部つんでしまうのがありかなぁと。
ちゃんと動作確認してませんが、Containerクラス作らない版?
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <boost/tokenizer.hpp>
#include <vector>
using namespace std;
template<typename T>
struct to
{
// tokenizerも使ってますし、boost::lexical_castでもいいとは思います。
T operator()(const std::string& str)
{
T tmp = T();
std::istringstream iss(str);
iss >> tmp;
return tmp;
}
};
template<> // std::string -> std::wstring等も用意した方がいいかも。
struct to<std::string>
{
std::string operator()(const std::string& str)
{
return str;
}
};
int main(void)
{
typedef boost::char_separator<char> char_separator;
typedef boost::tokenizer<char_separator> tokenizer;
static const int DATA_MAX = 8;
try
{
typedef std::string type;
// typedef double type; どちらなりと
vector<vector<type> > vcontainer;
ifstream ifs(d:/work/0301.csv);
if( !ifs || !ifs.is_open()) return -1;
char_separator sep(,, ", boost::keep_empty_tokens);
for(string line; getline(ifs,line); /**/)
{
vector<type> container;
container.reserve(DATA_MAX);
tokenizer tokens(line, sep);
// stringにするだけならcopyでもいいのですが。
std::transform(tokens.begin(), tokens.end(),
std::back_inserter(container), to<type>());
vcontainer.push_back(container);
}
}
catch(...) {
;// 握りつぶして捨ててるだけ
}
return 0;
}
typedef double type;に変えるとdoubleのvectorのvectorができる。
# でも簡単に動かしてみたら(doubleとか関係なく)、
# boost::keep_empty_tokensにしてるとtokenizerで余分な要素が取れちゃうっぽい。
# 何だろ。(XPpro,VC2008,boost1.45.0)
皆様お世話になります。
επιστημη さん
理解できました。このような場合、static にしてしまうと問題がありますね。
Ban さん
>tmpの結果が使われていないようですが…。
うまく説明できないのですが、私がtemplate クラスにこだわるのは、
template の柔軟さと、クラスの強力なコンストラクタの力を合わせて、取得する
データの型を判別して、実装者が欲する型のインスタンスを、多態的に
生成できないのだろうか?という発想からです。
>元コードにしても、一行=8の実装が switch(num % DATA_MAX)でよいくらいの制限で、
>非常に大きなデータ数を扱うなど固定サイズ化によるの性能改善を意識しないならば、
>一番素直なのはstd::vector<std::vector<std::string> >にでも
>(せいぜいreserve程度で)全部つんでしまうのがありかなぁと。
たしかにそうですね、紆余曲折、シンプルにたどり着く、それもありだと思います。
一旦解決とさせていただきます。