Tag Archives: C++

C++ テンプレート関数をソース・ファイルに書く

前提

まだ完全にはわからない

Tが汎用の場合

std::vector<T>などのTに何でも入れられることを前提にしてつくられているクラスはヘッダに書くしかないと思う。

Tが一部の型のみの場合

この場合はソースファイルにかける。

ここでは文字列の長さをを返す関数でchar*とwchar_t*をとるGetStringLength()を考える。

ヘッダ

最初のテンプレート関数は汎用のTを受け取る。もしテンプレート関数が実体化されたときはstatic_assertでエラーになるようにしている(sizeof(T)は決して0にならない。falseを指定してしまうと実体化しなくてもエラーになってしまう(コンパイラ依存))。char*とwchar_t*で特殊化するので、それ以外のポインタで呼ばれたときに実体化される。

次の2つは特殊化の宣言。定義はソースに書く。
次の2つは特殊化が実体化されるときの場所の指定。externでどこかにそれがあることを示している。

ソース

最初の2つは特殊化の定義。
次の2つは特殊化が定義されるときここに実体化されることを意味する。

main.cpp

今回の場合は実装がほぼないのでテンプレートにする意味があんまりないが、2つの実装がほぼ同じで、一部だけ書き換えたいときは汎用Tの方に実装を書くこともできる。その場合にこのテンプレートを使うこともできる。

Tが一部の型のみの場合(バージョン2)

ヘッダー

ソース&main.cpp

ソース:https://github.com/ambiesoft/blogprogs/tree/master/6038

考察

テンプレート関数の定義をソース・ファイルに書くと、他のソース・ファイルからは見ることができないのでリンカーでつなげることになる。よって鉤括弧なしのtemplateは実装を実体化し外部に公開して他のソース・ファイルから見えるようにしているのだと思われる。

鉤括弧ありのテンプレートはあくまでコンパイルフェーズで解決するものであり、宣言だけのテンプレートを実体化しても宣言だけになり、それがリンクされることもないのだと思われる。

C++のテンプレート関数で特定の型でエラーにする

std::is_class

is_class<T>を使うとTがクラス(構造体含む)かどうか判定してくれる。

テンプレート関数funcクラスや、クラスへのポインターや、クラスへのポインターのポインターを渡すとエラーになる。 ただしクラスへのポインターのポインターのポインターを渡すことはできる。

ソース

https://github.com/ambiesoft/blogprogs/tree/master/6022/isClass

テンプレートのvariadic引数で型をチェックする

普通の型チェック

Tがポインタだとエラーになる。

variadicの場合

最初の引数の型Tに対してチェックしている。CheckKataに渡される引数がwchar_t*だったりポインタのポインタだったらエラーになる。ただwchar_tはセーフにしている。

remove_cvなどの挙動がいまいちよくわからないのでこの書き方であっているのか不明。以下のようなコードで実行時の型を表示してくれる。

is_sameは渡された2つの型が同じならtrue
decayは配列参照などをポインタにしてくれる。
remove_cvconstvolatileを除去
remove_pointerはポインタを1つ除去する。

_vで終わるのはvalue,is_same::valueなどと同じ。
_tで終わるのはtype,remove_cv::typeなどと同じ。

ソース:https://github.com/ambiesoft/blogprogs/tree/master/6006/ConsoleApplication1

C#のRichTextBoxのフォントが途中で変わる

RichTextBoxのIMF_DUALFONTIMF_AUTOFONTフラグをクリアする。デフォルトでオンになっている。

参考:http://pineplanter.moo.jp/non-it-salaryman/2017/11/25/post-5255/

emplace_backでムーブコンストラクタがあるのにコピーコンストラクタが呼ばれる

puch_backよりもemplace_backがいいと言われていて実験したら、push_backだとコピーコンストラクタが呼ばれないのに、emplace_backだと呼ばれる現象が発生。

結論

ムーブコンストラクタにnoexceptをつければコピーコンストラクタの代わりにムーブコンストラクタが呼ばれる。

ソース:https://github.com/ambiesoft/blogprogs/tree/master/5767

C#のOpenFileDialogで拡張子exeの実行ファイルをフィルタして選択

C#とjavascriptの時間

基本

時間を表す言葉には時刻と時間間隔があるので時間という言葉ではあいまいになる。
どちらの場合も単位と基準点が問題になる。単位は秒とかミリ秒とかのこと、基準はUTCとか日本時間のこと。

Unix time stamp

UTCで1970/1/1からの秒を表す。今の値はこことかでわかる。

C#でこの値を得るには以下のコード

C#のDateTimeは0001/1/1からの100ナノ秒で管理しているようだ。3つの引数をとるコンストラクタはグレゴリオカレンダーで初期化するのでこれでいいらしい。

javscriptでこの値を得るには以下のコード

javascriptのDateはUTCで1970/1/1からのミリ秒で管理しているようだ。デフォルトのコンストラクタは今でgetTime()はミリ秒でUnix Epoch(=Unix time stamp)を返すので1000で割って秒にしている。

Unix time stampからオブジェクトをつくる

C#の場合は以下のようにやるらしい

これだとローカル時間が帰るので以下のように修正

javascriptの場合は以下

ソースコード

https://github.com/ambiesoft/blogprogs/tree/master/5705

enable_if

enable_ifによりある条件のときだけtemplateを有効にすることができる。逆に言うとtemplateにしたくない条件を無効化することができる。

std::enable_if_t<std::is_convertible_v<T, int>>std::enable_if<std::is_convertible<T, int>::value>::type>と同じことなのでこれについて考える。

全体としての意味はTintに変換できるときだけテンプレートを有効にするということ。

is_convertible<T, int>Tintに変換できるかを判定し、その結果はvalueに格納される。

enable_if<A>Atrueかどうかを判定し、trueならばtypeに型voidを格納する。falseならエラーになる。

よって全体としてTintに変換できない場合はエラーになり、templateのインスタンス化は行われない(コンパイルエラーにはならない(SFINAE))。

この例ではどういうときにこれを使うのかの応用例は示せていないが、特定の型のときだけテンプレートを有効にしたい場合に使う。

typename = としているのはtypename A = などと同じでデフォルトのテンプレート引数の指定、これはテンプレートのインスタンス化をするかどうかだけのために使われるので、コード中では使われないのでこういう記述になっている。

stringのvectorをスペースで区切って1つのstringにする


TLTR

ostringstreamとは

<<で渡された値を内部に持っているstringに追加していく。

ostream_iteratorとは

=で渡された値をコンストラクタで渡された出力ストリームに追加していく。
コンストラクタの2番めの引数はデリミタを指定する。=でストリームに追加したあとにこの値も追加する。デフォルトでは何も追加しない。
++演算では何もしない。これにより下記のcopyで役に立つ。

上のコードは以下のようにコンソールに出力される。

copyとは

第一引数と第二引数のイテレータで入力範囲を指定する。
第三引数で出力イテレータを指定する。

入力出力とも++で一個ずつずらしていって=でコピーする。

ostream_iteratorの++は何もしないで=で値をストリームに追加する。(最初のコード参照)