explicitで暗黙の型変換を防止する

先日書いた日記の補足。
以下のようなコードを書いてみると分かりますが、、、

#include <iostream>
#include <cassert>

using namespace std;

class M {
public:
  M(int i_):i(i_) { cout << "引数1個のコンストラクタだよ" << endl; } ;
  M(const M& m_):i(m_.i) { cout << "コピーコンストラクタだよ" << endl; }
  M &operator=(const M &o) { cout << "コピー代入演算子だよ" << endl; }

private:
  int i;
};

int main()
{
  M m1(1);     // (1)
  M m2 = 2;    // (2) 右辺値はM(2)に暗黙の型変換が行われる
  M m3 = M(3); // (3) (2)の記述と同じになる
}

暗黙の型変換が行われて、(2)と(3)の記述が同じになる。

わかりづらいのが以下の記事に書かれている例。
僕はC++を書いたころexplicitを使ったことがないへたれだった - 神様なんて信じない僕らのために

void hoge(M m_) {
    cout << "hoge:";
    m_.print();
}

こういうの定義して、

  hoge(m0);
  hoge(100); // これもOK


こんな書き方ができてしまう。これは分かりづらい><

Cクイズ こっちわからん><

/* MyTypeの定義 */

void set(MyType m, int val);
void inc(MyType m);
void print(MyType m);

int main(void)
{
MyType m;
set(m, 0); /* mを0にセット */
inc(m); /* mをインクリメント */
print(m); /* 1と表示される */
return 0;
}

/* 各関数の実装 */

このmain関数が、コメントにある期待通り動くようにMyTypeを定義し、各関数を実装することができるか?
もちろん、mainの中身は変えないこと。そして、使えるのは、C言語の言語要素のみ。

???ポインタを渡せるように構造体をtypedefするのか???

C++クイズ explicitコンストラクタ編

先輩から以下のような問題を出された。

【問題】
class MyClass {
public:
MyClass(int m_):m(m_) {} ;
private:
int m;
};
のようなクラスがある場合、

MyClass m1(0); // A
MyClass m2 = 0; // B
どっちの初期化もできちゃうよ。
この2つの違いはなーに?
どっちかしか使えない状況はある?

Aの場合は、普通にM(int m_)のコンストラクタが呼ばれて初期化が行われる。

Bの場合も、結果としては同じだけど、おそらく以下のような手順で初期化が行われる。

  1. 右辺値が一度 "M(0)" にキャストされ、
  2. private変数のmが0で初期化されたMクラスのインスタンスが生成され、
  3. 生成されたインスタンスが、Mクラスのデフォルトコピーコンストラクタでm2にコピーされる

M(int m_)のコンストラクタにexplicit宣言をつけた場合、Mのケースだとコンストラクタを明示しないといけないので、コンパイルエラーになるという話でいいんだろうか?

ソースコードのコメントよりも空白行のほうが理解を助ける

ソースコードのコメントよりも空白行のほうが理解を助けるという研究結果 - 森崎修司の「どうやってはかるの?

IEEE Transaction on Software Engineeringの論文Raymond P.L. Buse and Westley R. Weimer: Learning a Metric for Code Readabilityから。120人の被験者が10種類のオープンソースプロジェクトのソースコードの一部(20行等、非常に局所的)をもとに読みやすさに影響を与えることを実験結果から示している。

25種類のメトリクスと読みやすさとの相関を求めている。メトリクスには、コメント行数や予約語の数、空行の数、括弧の数、変数名の長さ、変数の個数などが含まれる。このうち、読みやすさに最も影響を与えやすいメトリクスとして、1 位に変数の個数、2位に行数、3位に括弧の数、9位に空行数、15位にコメント行数が示されている。

1位の変数の個数と2位の行数というのは割とありきたりで、この著者は15位のコメント行数より9位の空白行が上位にあることに関心を抱いたようです。

なぜコメントより空白行の方が理解度を助ける結果なのでしょう?

不思議だなーと思ったら、実験方法は以下のようなもの。
コード断片をたくさん見せて評価してもらっているそうです*1

10種類のオープンソースソースコードの断片を100箇所取り出し、それを被験者に評価してもらっている。

小さい規模のソースコードの場合、コメントをたくさん入れるより、意味ある単位を認識しやすくるように(コードを読みやすくするために)空白行を入れる方が効果的ということでしょうか?

もう少し大規模なソースコードだったらまた違う結果になりそうです。




というとこまで書いたところで、括弧の数 >>>> 空行数ということは、()だらけになる某言語は読みにくいということですか?

*1:評価の仕方は、元の論文(Learning a Metric for Code Readability)を見ないと分からないのが残念。

Android1.0でのセンサーの使い方

バージョン1.0の場合

初めてのAndroid

初めてのAndroid

はじめてのAndroidを参考にセンサーの使い方を調べています。
以下のblog記事によると、Android1.0/1.1とAndroid1.5でAPIが異なるそうです。

センサー(Sensor)を使用するには - 逆引きAndroid入門

今回は、はじめてのAndroidで紹介している1.0の方で。すでにバージョン2.0が公開されているご時世ですが、、、、^^;

サンプルは以下のURLから取得できます。
http://www.oreilly.co.jp/books/9784873114095/

package org.example.sensortest;

import android.app.Activity;
import android.hardware.SensorListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.widget.TextView;

public class SensorTest extends Activity implements SensorListener {
private SensorManager mgr;
private TextView output;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

// ...
mgr = (SensorManager) getSystemService(SENSOR_SERVICE);
output = (TextView) findViewById(R.id.output);
}


@Override
protected void onResume() {
super.onResume();

int sensors = SensorManager.SENSOR_ALL;
mgr.registerListener(this, sensors);

}

@Override
protected void onPause() {
super.onPause();
}

public void onAccuracyChanged(int sensor, int accuracy) {
// TODO Auto-generated method stub
}


public void onSensorChanged(int sensor, float[] values) {

StringBuilder builder = new StringBuilder();
builder.append("Sensor number: ");
builder.append(sensor);
builder.append("\nValues:\n");

for (int i = 0; i < values.length; i++) {
// ...
builder.append("[");
builder.append(values[i]);
builder.append("] = ");
builder.append("\n");
}
output.setText(builder);
}
}

このサンプルで利用されているSensorListenerインタフェースは、バージョン1.5以上では非推奨になっています。
このサンプルを見る限りでは、別タスクで動いているSensorManagerから指定したリスナに対して、センサーの値を送ってもらう形式になっているようです。
SensorManagerの動き自体は、1.5でも変わらないんじゃないかと予想しています。
中の動作については後日調査したいと思います。

SensorManagerクラス

1500行くらい。読むのはそれほど大変じゃなさそう。
今週の日曜日はActivityとIntentの調査に宛てるとして、来週あたりに調査しようと思います。

EclipseでAndroid SDKのソースコードを見る

EclipseAndroidアプリのデバッグをしている時に、SDKの主要なクラス(ActivityやIntentなど)のソースを参照したいときがあります。そういうとき、SDKソースコードは見れるようにした方が楽ですね。

手順は以下のとおり。若干面倒なので、詳しい手順は書きませんwww

Gitでソースコードを取得する

オフィシャルサイトの以下URLでソースコードを取得します。
http://source.android.com/download

Eclipseのプロジェクトでandroid.jarのソースコードの在処を設定する

上記の手順で手元にソースコードはある状態です。次にEclipseからソースコードを参照できるようにします。
以下のblogのやり方が参考になりました。

Android SDK ソース関連付け - Taosoftware
http://www.taosoftware.co.jp/blog/2008/11/android_sdk_1.html

ソースの関連付け
1.Androidプロジェクトを開き、プロパティを開く

2.Javaのビルドパス選択

3.ライブラリタグ選択

4.「外部jarの追加」「C:\android\android-sdk-windows-1.0_r1\android.jar」を選択

5.追加されたandroid.jarのソース添付を選択し、「編集」ボタンを押す。

6.先にソースを集めたディレクトリ「C:/android/android_source/jar_sources」を選択

7.Javadoc locationは、「Android Library」の内容と同じ物をセットする(file:/C:/android/android-sdk-windows-1.0_r1/docs/reference/)

8.最後にプロジェクト作成時に自動的に追加されていた、「Android Library」を削除

これでソースコードを参照できるようになっています。おけー!

Android用のTwitterアプリの開発を始めます

twitterアプリを作るよ

リクエスト募集 Twitterアプリを作ることを課題にしたらどうでしょう? - shibuyaandroid

この間、参加したshibuyaandroid(渋谷で開催されているAndroid勉強会)にて、Twitterアプリを作りませんか?という話題が出ています。
自分も自力でTwitterアプリを開発できるように準備を始めます。

twitter4jの利用準備

AndroidからTwitterにpostしたりするためには、TwitterのWeb APIを利用する必要があるみたいだけど、直接XMLをごにょごにょするのは面倒。処理を簡単に利用するJava APIを利用します。
名前はtwitter4j。

Twitter4J - A Java Library for Twitter API

これをダウンロードして、jarファイルにクラスパスを通します。

利用方法はサンプルを読むとよさそうです。
サンプルは「src/twitter4j/examples/」にあります。

これは中で、さらにライブラリを色々使っているようなので、他にも準備は必要みたい。必要なのは以下。

twitter4jからメッセージを送信する

Update.javaにコマンド引数を与えて実行するとTwitterアプリにpostできます。
第1引数がID、第2引数がパスワード、第3引数がメッセージ。

以下の箇所がTwitterにメッセージを送っている箇所です。
1行目でIDとパスワードを指定して、Twitterクラスのインスタンスを取得して、updateStatusメソッドでメッセージを送っています。

Twitter twitter = new Twitter(args[0], args[1]);
Status status = twitter.updateStatus(args[2]);
System.out.println("Successfully updated the status to [" + status.getText() + "].");

これはかなり簡単ですね。