2021年11月20日

シェルの `if` はパイプ出来る

最近「シェルスクリプトの if はパイプ出来る」という事を知った。bashでしか確認していないので、zsh等の別のシェルではどうか分からないが。

よく、コマンドの出力結果を行毎に走査する為に while にパイプするが、条件分岐の構文にパイプを適用するという発想は正直なかった……

# よく有るループの例
cat somefile.txt \
| while read line
do
    # ファイルの各行に対する何らかの処理:ここでは単に出力する
    echo $line
done

if へパイプを繋ぎ以下の用にすると、条件が真の時には then 節のコマンドに、偽の時には else 節のコマンドにパイプを繋いだかのように動作する。勿論、 if から別のコマンドへパイプを繋ぐ事も可能。

echo  "foo
bar" \
| if [[ $var = '' ]]
then
    head -n 1
else
    tail -n 1
fi \
| cat -n

# `var` が空文字列ならば:
# 1    foo
# そうでなければ:
# 1    bar

シェルの特色は「パイプで様々な処理を繋げる事が出来る」点だと分かっているつもりだったが、こんな事も出来たとは……奥が深い。

ラベル:Bash
posted by 天井冴太 at 09:00| Comment(0) | Study | 更新情報をチェックする

2015年05月24日

C#所感

いま関わっている仕事でC#を使ってる。この案件で初めてマトモにC#触って、割と言語の勉強と業務を並行してやってた。今度この案件から離れる事になったので、とりあえずC#の所感を書いておこうと思う。開発環境が Visual Studio 2008 だから、 C# 3.0 かな。去年の9月からだから、9ヶ月くらいの経験という事になるか。もっとも、その期間の半分以上は、何故か Visual Basic 6 を触ってた気がするが。


パーシャルクラス

C#の言語仕様として一番興味を惹かれたのがパーシャルクラス。これは、1つのクラスの定義を複数のファイルに分散できる仕組み。VSGUIデザイナが吐いたコードと、それで定義した各種GUIコンポーネントのイベントのコードを分離させる為に使われていたり、明らかにツールが自動生成したコードとユーザーが手で書くコードを分離する為の機能。言語仕様にツール連携の仕組みを入れるとか、IDE作ってる所らしいアイディアだと思う。

変数に対する「読み取り属性」の貧弱さ

個人的には、C#最大の欠点だと思う。ローカル変数とメソッドの引数に対して「読み取り専用属性」が付けられない。ので、少数の行数のコードを適切にメソッド分け出来る技量が無いと、アッという間に魔窟のようなコードが誕生する。チーム全員がそのレベルに達していれば良いんだけれど、残念な事に現実はそうとは限らない訳で。メソッドの引数は基本的に参照渡し(という言葉は正確でない気がするが)なので、ある変数の内容がメソッドの呼び出し前後で同じである事が保証されない。そのメソッドの役割的に不変の筈だと思えても、そうでないかもしれない。不具合対応の時に気をつけるべきコードが増えて閉口した。

もっとも、これはC#開発コミュニティも問題だと認識しているようなので、将来は解決されるんじゃないかなとは思う。

usingステートメント

usingで宣言したオブジェクトは、そのスコープを抜けた時に、オブジェクトが管理しているリソースが破棄される。詳しくはMSDNを参照

いや、分かる。そういう仕組みが必要な理由は分かる。でもガベコレ積んだ言語でこの仕様は正直キモイ。というか、ある型(の、オブジェクト)に対して、それがusingが必要か、そうでないか気をつける必要が在るという仕様は、あまり利口に思えない。型毎にデストラクタの実行タイミングを指定できるようにすれば良かったんじゃないだろか。スコープを抜けた時か、ガベコレに掃除された時か。

拡張メソッド

さながら、その型のメンバメソッドであるかのように、非メンバメソッドを呼び出せる。

C++の Extension Member Function イディオムっぽい。通常のメンバメソッド同様「.」演算子で呼び出せるので、より自然。だけどそれは一長一短で、例えば「obj.method();」というコードが在ったとして、果たして「method」は「obj」のメンバなのか、そうでないのか判別付きにくい。「method」の内容を読もうと「obj」のクラスの定義を見に行ったら、そこには無かった、という若干イラッとさせられる場面に何度か遭遇した。Enumerableインターフェイスの拡張メソッドを考えると、有用なのは確かなんだけど……まぁ、IDEの機能で探せ、という事なのかもしれない。

LINQとEnumerable

C#というより .NET Framework の範疇だけど。

LINQ良いよね。Enumerableの拡張メソッドも良いよね。でも共存してるのは微妙。同じ用途で使えて、同じキーワードが割り振られてて、でも微妙に書き方が異なる、ってのがどうも。

あと、こいつらは、どうも遅延評価する事になってるらしくて、VSのデバッガでステップ実行してたら想定外の場所に飛んでビックリなんて事が何度か。

いや瑣末な点なんだけど、ね。


総合的には、良い言語だと思う。上で述べたように幾つか気になる点が在って、特に変数の読み取り属性の欠落がキツイと感じるけど。 .NET Framework のMac/Linux展開も加速しそうだし、今後が楽しみな言語かなと。

続きを読む
ラベル:C#
posted by 天井冴太 at 21:09| Comment(0) | TrackBack(0) | Study | 更新情報をチェックする

2013年01月21日

Rubyの「範囲」は分かりづらい

読みやすいコードってどんなものか考えてみた -抽象化と名前重要- - 馬鹿と天才は紙一重

自分は果たして読みやすいコードを書けているのか、やや恐ろしく感じながら読んだ。

で、気づいた事その1。その2は後日その2はこちら。共通部分でなくとも抽象化

件の記事に以下のようなコードが在る。

Product.where(:price => 0..5)

このコードの0..5の部分、これは「0から5まで」という「範囲」を表すRubyの記法で、これの意味は"productモデルの中で、priceカラムの値が0から5までを取得"という事になる。

なるんだけれど、最初、以下のように誤読してしまい、その後の文の意味が一瞬解らなかった。

Product.where(:price => 0.5)

ドット(.を1つ見落としてしまった。これだと「priceカラムの値が0.5の物を取得」という事になってしまう。

"."なんて見た目ただの「点」なので認識しにくい事、認識しにくいこと。

ではどうすれば良いんだろう? ……括弧で囲ってみてはどうか。

Product.where(:price => (0..5))

単純な実数を括弧で囲う奴なんて先ず居ないだろうし。実数だとしたら不要な記述とする事で読み手の注意を引きつけようという魂胆。

或いは、空白で区切るのは?

Product.where(:price => 0 .. 5)

これがもし実数ならば、小数点の前後に空白を差し挟む事は出来ない(そもそもしない)ので、読み間違える事はないだろう。更にこの場合、仮にコーディング時にドットを1つ書き漏らしてしまっても、Syntax Errorになるので、直ぐに気づく事が出来そうだ。

……うーん、個人的には前者の方が好みかなぁ。メリットが多いのは後者だろうけど。

ラベル:ruby
posted by 天井冴太 at 02:10| Comment(2) | TrackBack(1) | Study | 更新情報をチェックする

2012年11月05日

Herokuのconfig varをローカル環境下のスクリプト内で取得するには(heroku-api版)

AMAgrammar <> PROgrammer: Herokuのconfig varをローカル環境下のスクリプト内で取得するには

……という記事を以前書いたが、何時の間にやらheroku gemを使う方法がdeprecatedになっており、以下のような感じで警告文が出力されるようになっていた。

require 'heroku'

EMAIL = '(Herokuに登録した時に使ったメールアドレス)'
PASSWORD = '(Herokuのパスワード)'
APPLICATION = '(アプリケーション名)'

heroku = Heroku::Client.new(EMAIL, PASSWORD)
vars = heroku.config_vars(APPLICATION)
 !    DEPRECATED: Heroku::Client#deprecate is deprecated, please use the heroku-api gem.
 !    DEPRECATED: More information available at https://github.com/heroku/heroku.rb
 !    DEPRECATED: Deprecated method called from /usr/lib/ruby/gems/1.9.1/gems/heroku-2.32.14/lib/heroku/client.rb:129.

どうやら今後はheroku-apiというgemを使えばいいらしい。早速gem installして、GitHubのREADME.md(と、heroku-apiのコード)を読みつつ書き換える。

require 'heroku-api'

EMAIL       = '(Herokuに登録した時に使ったメールアドレス)'
PASSWORD    = '(Herokuのパスワード)'
API_KEY     = '(API Key)'
APPLICATION = '(アプリケーション名)'
KEY         = '(値を取得したいconfig varのKEY)'

# API Keyが解っている場合
heroku = Heroku::API.new(:api_key => API_KEY)

# API Keyが解らない場合 (Thank you geemus!)
heroku  = Heroku::API.new(:username => EMAIL, :password => PASSWORD)

# APPLICATIONの全config varを取得
vars = heroku.get_config_vars(APPLICATION).body

pp vars

heroku-apiの各種APIの戻り値は大体Excon:Responseのインスタンスになってるっぽい。

以前は出来たHeroku::Auth.clientと同等の方法、herokuコマンドの認証情報を使うというのは出来なくなっているようだ。冷静に考えてみたら、herokuコマンドの認証情報を第三者のアプリケーションから利用出来るとか、セキュリティホールになり得るしねぇ。仕方ないか。

API Keyであれば、(以前の)メールアドレスとパスワードに拠る認証よりはセキュアなのではないか、多分。READMEに書かれているように、API Keyは環境変数HEROKU_API_KEYを設定しておけばそれを利用するようになっている。なお、API KeyはHerokuのAccountページから確認と再生成が可能だ。

ラベル:ruby heroku
posted by 天井冴太 at 17:00| Comment(0) | TrackBack(0) | Study | 更新情報をチェックする

なぜJavaScriptでは 10..toString() は動き、 10.toString() は動かないのか

javascript - Why 10..toString() works but 10.toString() does not? - Stack Overflow

非常に興味深かったので紹介。

ちょっとよく解らんっちゃけど。

152..toString(2)

これだとバイナリ文字列"10011000"が正しく生成されるっちゃけど、

152.toString(2)

これだと"SyntaxError: identifier starts immediately after numeric literal"って内容の例外が発生するっちゃんね。

なんで? 後者の方がまともな文で、前者は変な文に見えるっちゃけど?!

確かに。

回答を総合すると、これは、"."が複数の意味を持つ所為だという。即ち、小数点としてのそれと、"object member operator"としてのそれと。

JavaScriptの数値リテラルは小数点の前後の数値が0の場合は、それを省略する事が出来る(Final draft Standard ECMA-262 edition 5.1, March 2011 (Rev. 6) - Ecma-262.pdfの7.8.3 Numeric Literals)。

(1.) == (1.0)	// true
(.1) == (0.1)	// true

因って、"152.toString(2)"は、"152."迄で1つの数値リテラルトークンとして処理され、続く"toString"が解釈出来なくなりSyntax Errorとなるそうだ。

対し、"152..toString(2)"と"."を2つ連続させた場合は、1つ目が小数点、2つ目がobject member operatorとして解釈されるため、正しく処理出来ると。

言われて初めて気づいたが、確かに小数点とobject member operatorは同じ記号だ。あまりにも当たり前すぎて、今までまったく気にかけた事がなかったなぁ……

object member operator
この回答で使われていた言葉を拝借。オブジェクトとそのメンバを区切る"."記号の事。EcmaScriptの規格書を簡単に攫ってみたが、この"."の正式な名称はよく分からなかった。
ラベル:EcmaScript javascript
posted by 天井冴太 at 04:51| Comment(0) | TrackBack(0) | Study | 更新情報をチェックする

2012年07月04日

getsが返す文字列の末尾には漏れなく改行が付いてくる

お供が付いてくる!!!

v = STDIN.gets
if    v == "foo"   then puts '"foo"'
elsif v == "foo\n" then puts '"foo\n"'
else                    puts 'other'
end

このコードで、"foo"を入力した場合、以下の出力となる。

"foo\n"

改行要らない場合は、vに対しchomp呼ぶ。getsと同時にやっちゃうのが妥当か。

v = STDIN.gets.chomp
OAuthの認証で、STDIN.getsでPINコード入力させて、それをそのままoauth_verifierとして使ってたら、まぁ認証が通らない事通らない事。暫く嵌った。

参照文献

Rubyist Magazine - Ruby ではじめるプログラミング 【第 2 回】

ラベル:ruby
posted by 天井冴太 at 03:50| Comment(0) | TrackBack(0) | Study | 更新情報をチェックする

2012年03月19日

C++のthrowは式だった

送出式

throw expression

送出式が実行されると例外を送出する。送出式はvoid型である。

以上、送出式 - 標準C++辞典 - livedoor Wiki(ウィキ)より。

えっ、送出って事は、これ式だったのか?

という事は……


#include <iostream>
using namespace std;

int main() {
	try {
		true ? throw 1 : throw 2;
	} catch(int i) {
		cout << "throw : " << i << endl;
	}
}

……というコードを書いて実行してみると……

throw : 1

本当だ……条件演算内にthrow書いても問題ない。

これは知らなかった。しかしどういう時に役に立つんだろうこれ?

ラベル:C++
posted by 天井冴太 at 03:04| Comment(0) | TrackBack(0) | Study | 更新情報をチェックする

2011年09月07日

DOMで既存スタイルシートにルールを追加してはいけない

JavaScriptでスタイルシートを操作するには?

JavaScriptで既存HTMLページにCSSを追加する必要が出て来たのでちょっと調べた。
基本的に、document.styleSheetslink要素やstyle要素で読み込まれるスタイルシートが配列風(実際は配列ではない)に参照出来、insertRuleで新規にルールを追加出来るようだ(ただし例によってInternet Explorer以外。IE死ね!)。

const styleSheets = document.styleSheets;
// これで、
//  styleSheets[0] = 1つ目のlink或いはstyleで導入されているスタイルシート
//  styleSheets[1] = 2つ目のlink或いはstyleで導入されているスタイルシート
// ……といった感じでアクセス出来る。
const styleSheetsNum = styleSheets.length;	// スタイルシートの数

styleSheets[0].insertRule(	// ルールの追加;一番最初のスタイルシートに……
	"a { font-weight: bold; }",	 // ←のルールを……
	0);	// 0番目(対象スタイルシート先頭)に挿入。
const ruleNum = styleSheets[0].cssRules.length;	// ルールの数
styleSheets[0].insertRule("h1 { color: #000; }", ruleNum);	// ←で、スタイルシートの最後にルールを追加出来る。

で、こういった事を解説している、

なんかでは、document.styleSheetsの一番最後にルールを追加するようなコードを載せてる。

でもこれっておかしくない?

続きを読む
posted by 天井冴太 at 12:51| Comment(2) | TrackBack(0) | Study | 更新情報をチェックする

2011年08月29日

JavaScriptからチェックボックスのON/OFFを制御する

var elem = document.getElementById('checkbox_element');

みたいな感じで変数elemが操作対象のチェックボックス要素指してるとして、

  • elem.setAttribute()elem.removeAttribute()で操作 ←まちがい
  • elem.checkedで操作 ←せいかい!

以下テストコード

詳細はXHTMLソース自体を見て欲しいが、"change"ボタンを押す毎にその直前のチェックボックスのON/OFFを切り替える(事を意図している)。

Firefox 6.0、Opera 11.11、Chrome 13.0.782.112mで確認。例によってInternet Explorerはまともに動作しない。IE死ね!

なんか納得いかねぇ!

ラベル:HTML XHTML javascript DOM
posted by 天井冴太 at 20:22| Comment(0) | TrackBack(0) | Study | 更新情報をチェックする

2011年07月22日

C/C++で多次元配列を戻り値にするには

前回はC/C++で多次元配列を引数にとる方法を記した。引数があるなら戻り値はどうだ?というのか今回の趣旨。正確には『多次元配列を指すポインタ』な訳であるが。

結論から言うと、以下のようになる。

/* int[x][3]を指すポインタを返す関数 */
int (*function(int))[3];
int (*function(int))[3] {
	/* ... snip ... */
}

これは『配列を指すポインタ』の変数宣言とよく似ている。
また、前回挙げた引数の書き方(の1つ)ともよく似ている。

/* int[x][3]を指すポインタ */
int (*pointer)[3];
/* int[x][3]を指すポインタを引数とする関数 */
int function(int (*arg)[3]);

ただし、引数の場合と異なり、以下のような書き方は出来ない。

/* int[x][2](を指すポインタ)を返す関数……のつもり */
int functionX(int)[][2];	/* だがエラーだ */

引数の場合と同様、C++であればtemplateを用いて、一番右の次元の要素数を限定せずに書く事が出来る。

template<std::size_t N> int (*function(void))[N];
int (*ret1)[1] = function<1>();
int (*ret2)[2] = function<2>();

さらに次回に続く。

参考

ラベル:C C++
posted by 天井冴太 at 22:10| Comment(0) | TrackBack(1) | Study | 更新情報をチェックする

C/C++で多次元配列を引数に取るには

C言語学習時、確かに勉強した記憶があるんだが書き方忘れた。で、詰まった。
備忘録代わりにメモメモ。

int array[2][3];

なんて配列があって、これを引数に取る関数は、以下のようになる。

/* [x][3]な二次元配列を取る関数 */
int function(int arg[][3]);
int function(int (*arg)[3]);	// これでもおk

n次元配列の、右から数えてn-1次元目までは要素数を書かなければならない。
つまり、

/* [x][4][5]な三次元配列を取る関数 */
int function3(int arg[][4][5]);
/* [x][6][7][8]な三次元配列を取る関数 */
int function4(int arg[][6][7][8]);

ただし、

/* 1次元目も2次元目も何が来ても問題なく処理出来る関数……のつもり */
int functionX(int arg[][]);

みたいな真似は不可。
まぁ、C/C++の配列の仕様(添字が範囲外の値かどうかチェックしない)を考えると、この制限も納得なんだけど。

C++だとtemplate使えば上で挙げたような真似は一応出来る。

template<std::size_t N> int function(int arg[][N]);
int a[2][3], b[4][5];	// aとbの添字の数値が異なる点に注目
function(a);
function(b);

まぁこれで何が嬉しいかというと、例えばchar[][]から任意文字列を探すstd::find()の特殊化が出来るよね、とか。

次回に微妙に続く。

ラベル:C C++
posted by 天井冴太 at 01:44| Comment(0) | TrackBack(2) | Study | 更新情報をチェックする

2011年04月07日

Google Chromeでは、ローカル環境(fileスキーマ)下だと、object要素で読まれたHTMLから親のHTMLを読む事が出来ない

前回、object要素で読み込んだ(X)HTMLから、読み込み元のparam要素の内容を取得する方法の続き。

上記記事にて、

Chrome?さぁ、動くんじゃね?(投げやり)

……と、全くやる気がなかった件について。

先ずは前回のコードをローカル環境下のファイルに保存して、Chromeで開いてみてくれ。こいつをどう思う?
[動作せず]
すごく……動作してません……

そう、動作しない。HTTPでアクセスした場合は問題なく動作するのに、である。

Chromeのデベロッパーツールで確認してみると、in.htmlの16行目にてエラーが発生しているのが分かる。

in.html:16 Uncaught TypeError: Cannot call method 'getElementById' of undefined

……そんな馬鹿な!?

[window.parent.documentがundefined] 更に調べてみると、14行、window.parent.documentundefinedになっている事が分かる
[window.parentはDOMWindow型] window.parentは間違いなくDOMWindow型なのに、である。
undefinedな値にgetElementByIdメソッドが在る訳が無く、その結果、16行にてエラーが発生しているのだ。

これはバグ?それとも仕様?
仕様だとしたら一体どういう意図が……
HTTPサーバ立てて、そこで開発すれば問題は発生しないのだが、態々その為だけにサーバ導入するのも面倒だ……

posted by 天井冴太 at 04:40| Comment(0) | TrackBack(0) | Study | 更新情報をチェックする

2011年03月31日

object要素で読み込んだ(X)HTMLから、読み込み元のparam要素の内容を取得する方法

XHTMLHTML(以下単にHTMLと表記)のobject要素は、例えばFlashや各種動画ファイル等を読み込む為に使われるが、HTMLファイルを指定する事で、そのファイルをインラインフレーム表示出来る。

そして、object要素へ渡すパラメータ群は、子要素のparam要素で指定する事になっている。

……という事は、object要素で開いたHTMLからparam要素の内容を取得出来る筈だよね?という訳で調べてみた。

コード

結論としては以下の手法で。前者がobject要素を使う方(main.html)、後者がobject要素で読み込まれる方(in.html)。Firefox 4.0、Palemoon 3.6.15、Opera 11.0にて確認。

Chrome?さぁ、動くんじゃね?(投げやり)(別記事で言及する予定別記事にまとめた。Google Chromeでは、ローカル環境(fileスキーマ)下だと、object要素で読まれたHTMLから親のHTMLを読む事が出来ない)

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title>outer</title>
	<style type="text/css">/* <![CDATA[ */
		object { border: 1px dotted red; }
	/* ]]> */</style>
</head>

<body>
	<p>
		<object data="in.html" name="inner" id="inner">
			<param name="param1" value="value1" />
			<param name="param2" value="value2" />
		</object>
	</p>
</body>
</html>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title>inner</title>
	<style type="text/css">/* <![CDATA[ */
		/* objectで現れる境界線を消す
		 * via: http://www.usamimi.info/~geko/arch_web/03_memo/001_object/index.html
		 */
		html, body { border-style: none; }
	/* ]]> */</style>
	<script type="application/javascript"> // <![CDATA[
		function hoge() {
			var outerDoc = window.parent.document;	// 外部のHTMLのdocumentオブジェクト
			var obj;
			obj = outerDoc.getElementById("inner");
			var params = obj.getElementsByTagName("param");	// param要素群

			// param要素群の名前と値をリストアップする
			var i;
			var table = document.createElement("table");
			for(i = 0; i < params.length; ++i) {
				var tr = document.createElement("tr");
				var th = document.createElement("th");
				var td = document.createElement("td");
				th.innerHTML = params.item(i).getAttribute("name");	// param要素のname属性
				td.innerHTML = params.item(i).getAttribute("value");	// param要素のvalue属性
				tr.appendChild(th);
				tr.appendChild(td);
				table.appendChild(tr);
			}
			document.getElementById("paramsC").appendChild(table);
		}

		window.addEventListener("load", hoge, false);
	// ]]></script>
</head>

<body>
	<div id="paramsC"></div>
</body>
</html>

実動サンプルはこちら

では解説

先ずはmain.htmlから。

<object data="in.html" name="inner" id="inner">
	<param name="param1" value="value1" />
	<param name="param2" value="value2" />
</object>

object要素のdata属性に、読み込むHTMLファイル(ここではin.html)を指定。また、id属性を設定している点に注意。このid属性を元に、in.html側からparam要素の読み取りを行う。

次にin.html

var outerDoc = window.parent.document;	// 外部のHTMLのdocumentオブジェクト
var obj;
obj = outerDoc.getElementById("inner");
var params = obj.getElementsByTagName("param");	// param要素群

window.parentが読み込み元のHTMLのWindowオブジェクトに相当する。そこからdocumentを取得すれば、読み込み元HTMLをDOMに従って読み出す事が出来る(ただし書き込みは出来ない)。

よって、window.parent.documentgetElementByIdメソッドで取得したいparam要素を持つobjectを取得し、更にそのオブジェクトのgetElementsByTagNameメソッドを呼び出す事でparam要素(群)を取得出来る。

th.innerHTML = params.item(i).getAttribute("name");
td.innerHTML = params.item(i).getAttribute("value");

後は普通に各param要素のDOMノードからgetAttributeメソッドでname属性、value属性を読み出す事が可能。

IEの話

[object要素で読み込んだHTMLからparam要素を参照するサンプルをIE8で表示させた画面]全く正常に動きません。
開発者ツールも何処が悪いか教えてくれないので、全く原因不明です。
さぁ皆様声を合わせて!

またIEか!!!!!

ラベル:HTML XHTML javascript
posted by 天井冴太 at 00:42| Comment(0) | TrackBack(1) | Study | 更新情報をチェックする

2011年02月17日

operator=()は継承されない

#include <iostream>
using namespace std;

class C {
public:
	C() : v(0) {}
	int operator=(const int &rhs) { return v = rhs; }
//	int operator+=(const int &rhs) { return v += rhs; }	←=以外は問題ない
	int v;
};

struct  D : public C {
};

int main()
{
	D d;
	cout << d.v << endl;
	d = 10;
	cout << d.v << endl;
}

これが通らない。例えばVC++2010だと、

test.cpp(19) : error C2679: 二項演算子 '=' : 型 'int' の右オペランドを扱う演算子が見つかりません (または変換できません)。
		test.cpp(13): 'D &D::operator =(const D &)' の可能性があります。
		引数リスト '(D, int)' を一致させようとしているとき

……という感じのコンパイルエラーが発生する。

Dクラスを以下のようにすれば問題ない。

struct  D : public C {
	using C::operator=;	// ←これが要る
//	int operator=(const int &rhs) { return C::operator=(rhs); }	// ←或いはこれ
};

コード全体(と、実行結果)はideone.comを。

OK、継承されないという事も回避策も分かった。だが何故継承されないという仕様になっているのだろう?

ラベル:C++
posted by 天井冴太 at 16:49| Comment(0) | TrackBack(0) | Study | 更新情報をチェックする

2010年11月28日

Boost.PreprocessorのData Typesについて簡単にまとめてみる

どうにも同じようなC++コードを延々書かなければいけない→プリプロセサが在るじゃない!
という事で、C/C++でメタプログラミングをこなす為のライブラリであるBoost.Preprocessorに手を出した。

リファレンスはググったら簡単に見つかった

4つの型

さて、Boost.Preprocessorには4つの型が存在するようだ。全てマクロアーギュメントを複数格納するコンテナらしい。

オンラインリファレンスと、偶然図書館から借りていたC++テンプレートメタプログラミング(以下、単に『書籍』と表記)の付録Aを元にまとめてみる。同書籍に記述されている型名も括弧で囲って併記している。

sequences (列)

(a)(b)(c)のような、()で囲ったマクロアーギュメントの連続。

書籍によると、このライブラリのデータ構造の中で最も効率的で、最も柔軟性に富み、かつ最も使いやすいものであるとある。

要素数に制限無し。ただし、引数に数値を取るマクロでは256以下の値しか機能しない。尤も、BOOST_PP_SEQ_SUBSEQがあるし、それほど問題にはならないんじゃないだろうか?

tuples (タプル)

(a,b,c)のような、()の中でマクロアーギュメントを,で区切って記述したもの。

ランダムアクセスなど、いくつかの基本的な操作が用意されているらしいが、マクロの数も少なく(後述)、それ程実用的とは思えない……

関数やマクロの引数記述部分と同じ書き方というのが利点だろうか?

また、このデータ構造を操作する全てのマクロには、必ずtupleの要素数を指定しなければならない。つまりそれは、tupleの要素数を計算する方法がない、という事だろう。
arrays (配列)

(3, (a, b, c))のような、要素数と要素のtupleで構成されたもの。tupleの亜種と言えそうだ。

tupleと異なり、データ構造中にサイズを持つ

lists (リスト)

(a, (b, (c, BOOST_PP_NIL)))のような、『先頭要素とそれ以降のlist』で構成されたtuple亜種。終端にはBOOST_PP_NILを用いる必要がある。

LispのS式のように()の嵐になりそう。

これも、長さの制限は存在しない。

書籍によると、他の構造に比べて操作が遅くなりがちで、読みにくくなりがちなので、普通、最後の拠り所としてしか使われないとある。が、実はこのデータ構造を操作するマクロが一番多い(後述)。

データ構造中、或いはそれを扱うマクロの引数として、そのサイズが必要となるのがtuplesとarrays。それはつまり、自作マクロの引数としての利用は現実的ではないということだろう。その逆がsequencesとlists。

tuplesが一番C/C++の記述に近い。エディタ上での自動インデントの誤動作も少なくすみそう。これで、サイズを求める事さえ出来れば最高なのだが……

各型で可能な処理

……うーん、やっぱりよく分からない。いや表記の違いはよく分かったが、それぞれどういう時に使うのかがハッキリしない。

例えば、STL連接コンテナのvectorlistは違いがハッキリ分かる。vectorは要素の参照が素早く行える、listは要素の追加削除が容易。

Boost.Preprocessorの4つの型も、それぞれ何らかの長所短所がある筈だ。そうでなければ1つの型で充分な筈だし。

そこら辺をハッキリさせる為に、各型の操作を行うマクロをまとめてみた。『特定の操作を行うマクロが多ければ、その型はそれが得意と言う事だろう』という理屈。一つ一つ確認する余裕はないので、同じ名前のマクロは別の型を対象としていても同じ操作を提供する物と仮定。

arrays lists sequences tuples
マクロ数 16 44 36 7
BOOST_PP_ ~
LIST_APPEND


LIST_APPEND_D


LIST_AT


LIST_AT_D


LIST_CAT SEQ_CAT

LIST_CAT_D



SEQ_CAT_S

LIST_CONS*

ARRAY_DATA





TUPLE_EAT
ARRAY_ELEM
SEQ_ELEM TUPLE_ELEM

LIST_ENUM SEQ_ENUM

LIST_ENUM_R


LIST_FILTER SEQ_FILTER

LIST_FILTER_D



SEQ_FILTER_S

LIST_FIRST


LIST_FIRST_N SEQ_FIRST_N

LIST_FIRST_N_D


LIST_FOLD_LEFT SEQ_FOLD_LEFT

LIST_FOLD_LEFT_2ND*


LIST_FOLD_LEFT_2ND_D*


LIST_FOLD_LEFT_d


LIST_FOLD_LEFT_D*



SEQ_FOLD_LEFT_s

LIST_FOLD_RIGHT SEQ_FOLD_RIGHT

LIST_FOLD_RIGHT_2ND*


LIST_FOLD_RIGHT_2ND_D*


LIST_FOLD_RIGHT_d


LIST_FOLD_RIGHT_D*



SEQ_FOLD_RIGHT_s

LIST_FOR_EACH SEQ_FOR_EACH

LIST_FOR_EACH_I SEQ_FOR_EACH_I

LIST_FOR_EACH_I_R SEQ_FOR_EACH_I_R

LIST_FOR_EACH_PRODUCT SEQ_FOR_EACH_PRODUCT

LIST_FOR_EACH_PRODUCT_R SEQ_FOR_EACH_PRODUCT_R

LIST_FOR_EACH_R SEQ_FOR_EACH_R


SEQ_HEAD
ARRAY_INSERT
SEQ_INSERT
ARRAY_INSERT_D



LIST_IS_CONS SEQ_NIL

LIST_IS_NIL


LIST_NIL*

ARRAY_POP_BACK
SEQ_POP_BACK
ARRAY_POP_BACK_Z


ARRAY_POP_FRONT
SEQ_POP_FRONT
ARRAY_POP_FRONT_Z


ARRAY_PUSH_BACK
SEQ_PUSH_BACK
ARRAY_PUSH_FRONT
SEQ_PUSH_FRONT



TUPLE_REM



TUPLE_REM_CTOR
ARRAY_REMOVE
SEQ_REMOVE
ARRAY_REMOVE_D


ARRAY_REPLACE
SEQ_REPLACE
ARRAY_REPLACE_D



LIST_REST


LIST_REST_N SEQ_REST_N

LIST_REST_N_D

ARRAY_REVERSE LIST_REVERSE SEQ_REVERSE TUPLE_REVERSE

LIST_REVERSE_D



SEQ_REVERSE_S
ARRAY_SIZE LIST_SIZE SEQ_SIZE

LIST_SIZE_D



SEQ_SUBSEQ


SEQ_TAIL


SEQ_TO_ARRAY



TUPLE_TO_LIST



TUPLE_TO_SEQ

LIST_TO_TUPLE SEQ_TO_TUPLE

LIST_TO_TUPLE_R


LIST_TRANSFORM SEQ_TRANSFORM

LIST_TRANSFORM_D



SEQ_TRANSFORM_S

おい用意されているマクロ数に差が在りすぎるぞ。一番マクロが多いのがlists、一番少ないのがtuples。その差6倍。

さて、表にまとめてざっと眺めてみるに、次のような特徴が在りそうだ。

arrays
要素の追加削除に強い?
lists
その名の通り、順次処理に強いのだろうか。fold、for each、或いはreverseといった物が目立つ。
sequences
arraysとlistsの両方の特徴を併せ持っているように見える。ただし、それぞれの型で行える処理全てが可能という訳ではなさそうだ。
tuples
なにこれ。

tuplesの存在価値が謎。というかtuplesを操作するマクロの数が少な過ぎて判断が付かない。

各型の変換

表をまとめていて気づいたが、どうも、それぞれの型は相互変換可能という訳ではなさそうだ。図にまとめてみた。

[Boost.Preprocessor各型の変換マクロ一覧]listsとtuples、tuplesとsequencesは相互変換可能。sequencesからarrays、arraysからtuplesの変換は可能だが、その逆は用意されていない。 tuplesとlists、tuplesとsequencesは相互変換が可能。しかし、それ以外の変換は片方向のみ、或いは全く用意されていない。また、arraysに関してはtuplesへの変換しか用意されておらず、名称も他のものとは異なる。

マクロアーギュメント

書籍C++テンプレートメタプログラミングから用語を拝借。

マクロアーギュメントとは、次のものの空でない列である。

  • コンマでも括弧でもない、1つ以上のプリプロセッサトークン、および(または)
  • 左右の括弧に囲まれた、1つ以上のプリプロセッサトークン。
それ以外の変換は片方向のみ、或いは全く用意されていない
例えばlistsとsequencesの変換であれば、tuplesへの変換を経由すれば可能ではある。
ラベル:C++ boost
posted by 天井冴太 at 04:33| Comment(0) | TrackBack(0) | Study | 更新情報をチェックする

2010年10月07日

Rubyではメソッドは呼び出す前に定義してしまわなければならない

らしい。

以下のコードはダメ。

f

def f
	puts "call f"
end
/cygdrive/d/Documents and Settings/amaisaeta/test.rb:1: undefined local variable
or method `f' for main:Object (NameError)

なので、定義を先に書かなければならない。

def f
	puts "call f"
end

f
call f

最初、メソッドの定義を後回しにしてたらエラーになって驚いた。

えー、これダメなのか。メソッドの定義を後回しに出来る言語なんて沢山あるぞ。なんでダメなんだろう。どう考えても、後に書けた方が可読性高くなりそうなのに。

ラベル:ruby
posted by 天井冴太 at 03:21| Comment(0) | TrackBack(0) | Study | 更新情報をチェックする

2010年10月01日

例外のcatch時に変換関数は適用されない

いやようするに、

#include <iostream>
#include <stdexcept>
using namespace std;

struct C {
	operator runtime_error() {
		return runtime_error("original description");
	}
};

int main()
{
	try {
		throw C();
	} catch(runtime_error &) { // (1)ここには来ないで……
		cout << "catch std::runtime_error!" << endl;
	} catch(...) { // (2)ここに来る
		cout << "catch some type..." << endl;
	}
}

てな感じで、変換関数が定義されたクラスをthrowしても、catchする時にはそれは適用されない。らしい。驚いた。

なんかあんまり直感的でないなー。なんでこうなっているんだろう。

ラベル:C++
posted by 天井冴太 at 03:13| Comment(0) | TrackBack(0) | Study | 更新情報をチェックする

2010年08月07日

C++の継承と条件演算子の話

C++で次のようなプログラムを書いて……


struct C { };
struct D : C { };
struct E : C { };

int main()
{
	bool expr = true; // 実際にはexprの値を決めるごにょごにょが在る
	C *p = expr ? new D() : new E();

	return 0;
}

コンパイルすると……


>cl test.cpp
Microsoft(R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

test.cpp
test.cpp(8) : error C2446: ':' : 'E *' 型から 'D *' 型への変換ができません。
        指示された型は関連がありません。変換には reinterpret_cast、C スタイル キャストまたは関数スタイルのキャストが必要です。

こうなった。

えー、DECの派生クラスだからC *に突っ込んで文句言われる筋合いはないぞー?とちょっと悩んだ。

よく考えたら、

expr ? new D() : new E()

この条件演算、結果の型は何やねん、という。条件が真の場合はD *で、偽の場合はE *?一つの式で結果の型が異なるとかそんなアホな。

結局、


C *p;
if(expr) p = new D();
else     p = new E();

或いは、

C *p = expr ? static_cast<C *>(new D()) : static_cast<C *>(new E());

と書けと。

『派生先のポインタは派生元のポインタにキャスト無しで入れられる』という常識に気をとられて何も考えず書いた結果がこれだよ!反省。

コンパイル
今回はVC++2010 Expressのclを利用。
ラベル:C++
posted by 天井冴太 at 04:46| Comment(0) | TrackBack(0) | Study | 更新情報をチェックする

2010年05月13日

Seesaaブログでは、検索結果のページ、特定タグのページで記事コンテンツが表示されない

SeesaaブログのHTMLをカスタマイズしようといろいろ弄っているが、調べれば調べる程絶望感が押し寄せてくる。ある変数が特定の条件下で参照出来ないなんてざら。なんと中途半端な実装。BlogServerという名でASPとして他社に提供しているらしいけど、よくこんなキモい仕様のモノで金取ろうと出来るねホント。

愚痴はここまで。
それでは本題。といってもタイトルで全内容言い終わってるんだけど。

Seesaaブログで開設しているblog上でblog内検索を行うと、検索結果が一覧表示される。例えばこのblogを"プログラミング"で検索するとこう表示される。この時、検索結果一覧を表示するページである事を識別出来るように、page_name変数にはsearchという文字列がセットされる。
同様に、特定のタグが付いた記事や各種ファイルを一覧するページ(例えば"C++"タグならこう)も存在し、この場合はpage_nameにはtagがセットされる。

これら2つのページにおいて、記事コンテンツは強制的に非表示となる記事コンテンツとは、blog中で記事(例えばこの文章)が表示される部分の事である。個別記事のページであれば、1つの記事の全文とそれに付けられたコメントやtrackbackを、トップページやカテゴリ別の記事一覧ページ、特定年月の過去ログのページでは、条件に合う複数の記事の表示を担当する。

……道理で、検索結果一覧とタグ別のページのHTMLが、記事コンテンツではなく、大本のHTMLに書かれている訳だ。てっきりpage_nameの内容を見て条件分岐しているだけかと思っていた。

何故この様な仕様になったんだか……理解出来ない。

posted by 天井冴太 at 03:55| Comment(0) | TrackBack(0) | Study | 更新情報をチェックする

2010年04月26日

Seesaaブログ独自タグ内では、2項を超える多項式が書けない

そういえば前回書き忘れてたんだけど、Seesaaブログの独自タグ内では2項を超える多項式が書けない。括弧使えば出来るけど。

例えば、

<% echo(1 + 2) %>

……は可能(期待通り"3"が表示される)だが、

<% ehco(1 + 2 + 3) %>

……は不可能(処理がエラーになるのか、同コンテンツ全てが表示されない)。

どうしても、というならば、前述の通り括弧を使えば出来ない事はない。

<% echo((1 + 2) + 3) %>

……でもこれって、1~9までの総和を求める式書こうと思ったら、

<% echo((((((((1 + 2) + 3) + 4) + 5) + 6) + 7) + 8) + 9) %>

……って書かなきゃいけないって事で。

まぁ、これは流石に書く機会無いだろうけど、Seesaaブログの独自タグ <% if %> で、論理演算する方法の手法使って、ちょっと複雑な条件書こうと思ったら途端に負担となる。

演算処理を実装するのは良いが、なんでこう項中途半端なの……

posted by 天井冴太 at 02:34| Comment(0) | TrackBack(0) | Study | 更新情報をチェックする

広告


この広告は60日以上更新がないブログに表示がされております。

以下のいずれかの方法で非表示にすることが可能です。

・記事の投稿、編集をおこなう
・マイブログの【設定】 > 【広告設定】 より、「60日間更新が無い場合」 の 「広告を表示しない」にチェックを入れて保存する。