2016年5月24日火曜日

Excel VBA最初の一歩: とりあえずメッセージボックスを出す

細かいツールのプログラムを作成する環境として、Excel VBAが結構普及しているようなので、
少し前から勉強しようと思っていました。

簡単なツールを作成する機会があったので、基本から調べたことをメモしています。

まず今回は最初の一歩。とりあえずVBAメッセージボックスを出すところまで。

環境

  • Windows 10
  • Excel 2016 (最近のバージョンなら同じ手順だと思います。)

1. Excel 2016を起動する





2. Visual Basicウィンドウを開く


ショートカットは Alt + F11 (要暗記!)





3. コードを書く場所(標準モジュール)を作成


プロジェクトの右クリックメニューから「挿入」「標準モジュール」を選択


4. コードを書く


4行だけです。
下のコードで、Helloというサブルーチンがマクロとして登録されます。

Option Explicit

Sub Hello()
    MsgBox "Hello"
End Sub



5. Visual Basicウィンドウから入力したコードを実行してみる



 F5で実行できます。
 マクロ名でHelloを選択して、実行ボタンをクリックします。



6. 実行結果


無事メッセージボックスが表示されました。



7. Excelシートからマクロを呼ぶ

普段はわざわざVisual Basicウィンドウを開かずにVBAを実行したいですよね。
そのためにはここではまず図形を追加します。



8. 図形にマクロを登録する


図形を右クリックして、「マクロの登録」を選択します。





9. 登録するマクロを選択します。


ここではHello。



10. 同じようにメッセージボックスが表示されました。






ここまでくれば、あとはVisual Basicウィンドウのエディタでコードを書けばいろいろなことができそうです。









2016年5月11日水曜日

[C++] 引数の型も個数も不定な関数を定義したいのでBoost.Preprocessorを試す

複数の変数の値を適当なフォーマットでログに出す関数を作成しているとします。

呼び出し側はこんな感じ。

int a;
string b;
ClassA c;
logFunction(a, b, c);

色々な型の引数をもつ関数を定義するなら関数テンプレート。
引数が1つの場合こんな感じになります。

template 
void logFunction(T arg) {
  DO_SOMETHING(arg);
}


DO_SOMETHINGは、

std::cout << arg;


みたいないろいろな型を受けられるようにになっているものをイメージしてください。

ですが、さらに引数の型も数も不定な場合、どうしようかと。

最近ならC++11以降の可変長引数テンプレート(Variadic template)でできるのでしょうが、
残念ながらコンパイラのバージョンが古くて使えない状況。。

最初はごり押しで書いてみました。

template <typename T0, typename T1>
void logFunction(T0 arg0, T1 arg1) {
  DO_SOMETHING(arg0);
  DO_SOMETHING(arg1);
}
template <typename T0, typename T1, typename T3>
void logFunction(T0 arg0, T1 arg1, T2 arg2) {
  DO_SOMETHING(arg0);
  DO_SOMETHING(arg1);
  DO_SOMETHING(arg2);
}
.
.
.

しかしいつの間にか引数が数十個まで必要になってしまい冗長にもほどがある状態になってしまいました。


Boost.Preprocessor


ある日、この肥大化した関数たちの処理を修正したいときがきまして、
そろそろなんとかしようかなと適当に検索していたら
Boost.Preprocessorでできそうな気がしてきました。
(繰り返しになりますが最近のコンパイラならVariadic templateでできそう)。

数少ない手に入るサンプルをこねくり回して作成したのが下記のコード。
これで引数25個まで一気に定義できます。
MAX_SIZEを変えればもっと多くてもできそうです。




#include <boost/preprocessor/repetition.hpp>
#include <boost/preprocessor/punctuation/comma_if.hpp>

#define MAX_SIZE 25

#define repSomething(z, n, unused) \
DO_SOMETHING(arg##n);\

#define DefLogFunction(z, n, unused) \
template <typename T BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename T)> \
void logFunction(\
T arg\
BOOST_PP_COMMA_IF(n) \
BOOST_PP_ENUM_BINARY_PARAMS(n,T,arg) \
) {\
DO_SOMETHING(arg);\
BOOST_PP_REPEAT(n, repSomething, ~)\
}\


BOOST_PP_REPEAT(MAX_SIZE, DefLogFunction, ~)


#undef DefLogFunction
#undef repSomething