Developers Summit 2011 行ってきた!

ある日突然上司から「デブサミ行く気ない?」と言われたときはデブですいませんと思ったものでしたが締切直前に滑り込みで登録、満席のセッションを目にさらしてアジャイル開発だけに的を絞って登録――というプロセスを経て本日行ってきました。スーツが多かった(感想はそれか)。明日は行く予定がありません……ははは。明日はTDD関連があるからちょっと興味はあるんだけどあえて今日にしたんですよ。ははは。
興奮覚めやらぬうちにとりあえず書いとく。しかしTwitter実況があるから入れなくてもかぶって入れなかったとしても結構普通に内容がわかるのなー。ありがたい時代だ。
http://twitter.com/#!/search?q=%23devsumi
続々と資料うpられ中。録画動画なども。これ会場行かなくてもいいんじゃね?(んなーこたない

  • 17-B-2:アジャイル開発実戦 →かんそう:うちの上司もその上司もアジャイルに乗り気だからなー品証ていうかISOだけじゃね、問題は
  • Jum Session: G* →かんそう:うおお空気読めてなかったかもでも面白かったし冊子ありがとうございます!これから読みます(マテ
  • 17-B-5:今そこにあるScrum →かんそう:やっべえredmineとScrumはすごく相性がよさげなうえにおれTDD大好きだからちょいちょいとできそうなきがするけどScrumよくわかってNEEEEEEE そしてドヤ顔に吹いた

ほか会場には入れんかったけどTwitter実況(#devsumi)&TogetterまとめでRedmine チケット駆動開発なんかもざざっと要点は。
http://togetter.com/li/102077

個人的にはScrum面白かったー。あと昼にJum SessionでやってたTDDの聞けばよかったなぁ。なんか面白かったっぽいし。どうせ店混んでるんだからそこだけ聞いて遅れてから行けばよかったとすごく後悔。

Grooveyとか

おれは基本的にJavaを全然書かないひとなので(基本的なのは一応かけるしC#は書くので読めるは読める)あんま使う機会はなさそうだけどちょろちょろとObjective-Cぽいなーとか思ったりした。あの簡潔さ素晴らしい。C++は何かとめんどっちいんだよなー。ガベレージコレクションもねーし。あとJavaってHudsonJenkinsとの連携が良かったりEclipseプラグインいっぱいあったりとかしてほんとに環境がいいよなー。あとテストの記述量少ないのはいいなぁ(またテストか)。関係ないけどMacbook Airの所持率高杉。

Scrum

まず俺あんまりScrumについて知らないんだけど要点を調べてみると

  • プロダクトオーナー:プロダクト責任者
  • 開発チーム
  • すくらむマスター:開発の支援者(管理者とは微妙に意味合いが違うぽい?PMに近いらしい。関係ないけどひらがなでかくとぽけもんマスターぽい


開発チームのやること:実装とテスト&みんなで協力して問題を解決する

特色:

  • プロダクトオーナーが持ってきた要求から作業を細分化する
  • 2〜4週間で動くものができる(テストが完了する)ように計画をたてる
  • 短いスパンでの進捗確認&効率を重視して各人が積極的に仕事をすすめる。進捗確認が終わって問題が特にないならあとは開発に集中。
  • 動くものができたら反省会をして次のスプリント(実装&テスト)にフィードバックする(←ここ重要

XPとの違いがいまいちわからない……まぁ本質的には同じだという話だったからいいのかな。比較的プロセス側の観点から話してるだけでやること事態は同じなのかも。ちなみにひとつのスプリントに入る前に仕様ドキュメントは完成している必要があるらしい(Wikipediaより)

これはうけた。
「良くない朝会。ボソボソ喋る。チームに対して話さない。多分今日終わるはず・・・。自分でタスクを取れない。メンバーが助けを求めていても知らんぷり。」あるあるww


うちでやってる中で(Scrumではないけど割と近いことはやってる)できてないことだと、

  • チケットの細分化→これ細分化するのはいいけどちゃんと管理しないとだめだからそこら辺の話はRedmineまとめ参照。
  • タスクを取らない(もしくは自分で取る人が限られている)
  • 朝ミーティングが長い!

あたりだなーとか思いながら聞いた。あとウォーターフォールなのでやっぱり期間が長いですね。実装期間自体はフェーズ分けたりver0.xxとかにしたりして短めにするようになってるから長くても一ヶ月程度だけど、検証含めると二ヶ月はかかる計算だし、基本設計ができるまでは次に行けないしなー。まぁ基本設計と言って曖昧にごまかしている部分はあるんだけども……。

今日の話を聞く限りは作業は一日から二日で終わる粒度にまで細分化されている必要があるような気がする。「多分今日中には…」と朝ミーティングでいっているときはなんで多分…って思うのかということに関して注意が必要?なにか気になることがある、うまくいかないことがある、ボトルネックがある場合は口にしようね、って言ってた。そして周りの人は目を逸らしたりせずに一緒に解決案について考えましょう、とのこと。
朝ミーティングででた懸念事項で短い時間内で解決できない場合は、朝MT後すぐに関係者で話し合う場を設けるってのはやってないなー。ちょいちょいと先延ばしにしたり午後一で…とかになっちゃうけどまぁでもそこら辺は運用の範囲か。

あーRedmine聞けなかったのマジで残念だった……。くそー。

Redmine チケット駆動開発(俺的メモ)

要点まとめ(まとめから見る限りだけど)。後ろの記号はすでにやってるか否かです。
参考はこちら:http://togetter.com/li/102077

  • チケットは作業の漏れをなくすだけでなく,ものづくりをもうちょっと楽しくするもの ?
  • TiDD開発プロセスの即時性・効率化に寄与する
  • チケット無しに構成管理上の変更をしない ×
  • 変更の議論をチケットとして残しておく △(啓蒙中)
  • 完全チケット方式 1. チケットがすべての作業を管理する 2. プロセスを変更するので社内調整が必要 ×
  • 補完チケット方式 1. 既存の管理は変更しない 2. こっそり始められる ○(グループ内でだけど)
  • チケット駆動による従来課題の解決: コミュニケーションのオンライン化 → 情報はRSSなどで即時に展開 △(プラグインとか必要、でもやっぱりアジャイルなら叩頭コミュニケーションも必要じゃない?)
  • 問題解決支援- チケットによるトレーサビリテイ向上,作業スコープ(今日やること・優先度とか)の明確化.XPのタスクカードのイメージ △(人に寄るなぁ。ここら辺を意識してる人と単なる工数管理ツールだと思ってる人と)
  • フィーチャーフリーズ、リリーススプリント (これよくわからない。フィーチャーフリーズはテストが一定値以下だったらソースコードの開発を止めることらしい。リリーススプリントはスクラムのはなし?)
  • 親チケット=ストーリー、子チケット=タスク ○
  • チケットの取捨選択が本来のマネジメント △(キャンセルとか保留とかをちゃんと使わないとですね)

見ていく限り作業の細分化をして適切な粒度のチケットをつくる必要性は感じる。多分感覚的に一日か二日でできる程度の粒度までは下げる必要があるだろうなぁ。でも三時間とかにしちゃうとものによるけど苦しい。
あと、TLで見かけた気がするんだけど、「チケットの定期的な棚卸」が必要とのこと。あるあるwwww

僕が基本的に個人で気をつけていることとしては

  • まず先にチケットをつくってから作業する。突発的な作業が発生したらチケットを作成してから作業する。
  • チケット進捗状況は割とこまめに変える(今どうなっているかを他の人からも分かるようにする)
  • レビュー前に一つの親のレビュー以外のチケットをすべて閉じる→レビュー反映はレビュー作業の一環なのでレビューのチケットにつける
  • ドキュメントはプロセス管理対象なのでいいんだけどコードレビューは口頭でやって指摘がなかった場合はエビデンスが残らないので、レビュー依頼チケットを出す(←New!)

テストに関しては他の人がいろいろと枠組みつくってやっているのでまだ俺はよくわかってないけど、チケット見れば全部わかるようになってるな。実はテストって結構チケット駆動と相性がいいと思うんだよなー。とかとか。

google test/mock導入

どうもこんにちは。google信者です。アンドロイドほしーい(というキャンペーンはやっておりません
信者なのでいけてるユニットテストライブラリgoogle test(およびgoogle mock)を紹介することにした。C++専用です*1 *2CppUnitよりは確実にかなり断然記述量が少なくてお勧めです。結果も色で表示されるし!

インストール

http://www10.atwiki.jp/bambooflow/pages/187.html
基本はここのとおり。

  1. とりあえずtar.bz2ファイルをダウンロードしてきて展開
  2. 適当なところにgtestフォルダを作成
# mkdir /home/wonodas/gtest
  1. 後は中身をメイクするだけ!
# cd /home/wondoas/Desktop/gtest-x.x.x/
# ./configure --prefix=/home/wonodas/gtest --enable-shared=no
# make
# make install

これで さっきつくったgtestのところにライブラリが展開される。

2011.4.21追記

1.6.0にアップデートしようとしたんだけど、make installをしようとしたら、

make install is dangerous and not supported. Instead, see README for how to integrate Google Test into your build system

と出てきてしまった。cmakeを使うことを推奨しているぽい。makeまでは今まで通りでOKなんだけどmakeのあとに

g++ -I ${GTEST_DIR}/include -I ${GTEST_DIR} -c ${GTEST_DIR}/src/gtest-all.cc
#libgtest.aを作成する
ar -rv libgtest.a gtest-all.o

とする必要があるもよう。

使い方

Eclipse(Helios)での使い方。

  1. とりあえずテストプロジェクトを作成
  2. テストプロジェクトの環境設定で、[Settings]-[Tool Settings]-[GCC C++ Compiler]-[Includes]でgtest/includeを指定
  3. 同じくLibraries search pathでgtest/libを指定
  4. 同じくLibraliesでgtestを設定
  5. なんかマルチスレッド関連のエラーが出たので一応pthreadもライブラリに追加

ここまでで一応コンパイルは出来るようになる。
書くときは

#include <gtest/gtest.h>

(省略)

TEST(テスト名、ユニークな名前){
(テストの内容)
}

int main(int argc, char** argv){
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

"テスト名_ユニークな名前"で一つのテストケースとして認識されるようなのでドキュメントには「アンダースコアを使ってはいけない」と書いてあった。
アンダースコアを使ってはいけないことが分かる例
ex.)
TEST(A_Test, constructor) →A_Test_constructorというテストケースとして認識
TEST(A, Test_constructor) →A_Test_constructorというテストケースとして認識
↑上二つの区別が実行時にわからなくなってしまう…とのこと

テスト名を「テストするクラス名+Test」, ユニークな名前を「test+何をテストしているかわかるような名前」にしておけばあまり問題は起きないような。まぁ一応推奨されている通りにやった方がいいんだろうけど…。

なおHudsonで自動ビルドするよ!とかいう場合はJUnit形式のxmlファイルを吐きだしてくれるので結果を表示することができます。
実行時のオプションに--gtest_output=xmlをつけてやればtest_detail.xmlという結果ファイルが実行ディレクトリにできるよ!Linux詳しくない人のために一応書いとこう。

#unitTestingという実行ファイルを実行する
./unitTesting --gtest_output=xml

[参考]
http://opencv.jp/googletestdocs/advancedguide.html#adv-generating-an-xml-report

*1:ちなみにC#のときは全力でMoqをおすすめする。さらにhtmlでソースコードの色分けをしたい場合は全力でgoogle-code-prettifyだ!!

*2:google-code-prettifyに関しては以下を参照!地味に.jsいじるがいいさhttp://webos-goodies.jp/archives/51202317.html

googlemockのつかいかたまとめ

http://src.chromium.org/svn/trunk/src/remoting/client/chromoting_view_unittest.cc
ここらへんとかを読み解きながら。

基本の書き方

class Hoge{
public:
    Hoge(){};
    ~Hoge(){};

public:
    int hogeMethod1(int x){ return x;};
};

というクラスがあった時は、まずモッククラスを作成する。

using ::testing::Mock;
using ::testing::_;
using ::testing::Invoke;
using ::testing::Return;

class MockHoge : public Hoge{
public:
    MockHoge(){
        //モックのメソッドが呼び出されたときに、Hogeクラスの対応するメソッドを呼び出すように設定する(書かなくてもよい)
        ON_CALL(*this, hogeMethod1(_)).WillByDefault(Invoke(&hoge_, &Hoge::hogeMethod1));
    };
    //デコンストラクタはvirtualにすると書いてあったけどしなくてもよいかも?
    virtual ~MockHoge(){};

    //引数が0だったらMOCK_METHOD0, 1だったらMOCK_METHOD1,...と書いていく
    //第1引数はメソッド名、第二引数は"戻り値(引数)"
  MOCK_METHOD1(hogeMethod1, int(int));

private:
    Hoge hoge_;  //ON_CALL用。コンストラクタで書かない場合はいらない。
};

テストメソッドは以下のようにかく。

//TEST(任意、任意)
TEST(MockHogeTest, invokeTest){
    MockHoge mh;
    //引数が何であってもよい。1回呼ばれたらsuccessを返してくれる
    EXPECT_CALL(mh, hogeMethod1(_)).Times(1);
    EXPECT_EQ(1, mh.hogeMethod1(1));

    //引数指定、WillOnce(Return(戻り値))で戻り値が本来かえってくるものとは別のものを指定することも可
    EXPECT_CALL(mh, hogeMethod1(1)).Times(1).WillOnce(Return(10));
    EXPECT_EQ(10, mh.hogeMethod1(1));
}

あるメソッドの中で同じクラスのメソッドが呼び出されることがあって、それをテストしたい場合はやり方が少し違うので注意。
例えばこんなクラスがあったとする。

class Calc{
public:
    Calc(){};
    ~Calc(){};

    int shiftUpNBit(int x, int n){ return x << n; };
    int shiftDownNBit(int x, int n){ return x << n; };
    bool isEven(int x){ return x % 2 == 0; };
    //偶数だったらnビット左にシフト、奇数だったらnビット右にシフトする
    int calc(int x, int n){ return isEven(x) ? shiftUpNBit(x, n) : shigtDownNBit(x, n); };
};

calcを呼ぶと中でCalcクラスのshiftUpNBit, shiftDownNBit, isEvenが呼ばれる。全部pubicにしてるけど…

class MockCalc : public Calc{
public:
    MockCalc(){
        ON_CALL(*this, shiftUpNBit(_, _)).WillByDefault(Invoke(&calc_, &Calc::shiftUpNBit));
        ON_CALL(*this, shiftDownNBit(_, _)).WillByDefault(Invoke(&calc_, &Calc::shiftDownNBit));
        ON_CALL(*this, isEven(_)).WillByDefault(Invoke(&calc_, &Calc::isEven));
        ON_CALL(*this, calc(_, _)).WillByDefault(Invoke(&calc_, &Calc::calc));
    };
    virtual ~MockCalc(){};

public:
    MOCK_METHOD2(shiftUpNBit, int(int, int));
    MOCK_METHOD2(shitDownNBit, int(int, int));
    MOCK_METHOD1(isEven, bool(int));
    MOCK_METHOD1(calc, int(int, int));

private:
    Calc calc_;
};

ここまではその上とおんなじだが。

TEST(CalcTest, testCalcInvoke){
    //ヒープ領域に取らないとエラーが出るぽい
    MockCalc* mc = new MockCalc();
    {
        //順番のテストとメソッドの中でちゃんとメソッドが呼び出されているかテストする(EXPECT_CALLはまちがいでON_CALLが正しいです;#2011/2/17)
        InSequence s;
        EXPECT_CALL(*mc, calc(_, _));
        EXPECT_CALL(*mc, isEven(_)).WillOnce(Return(true));  //どんな場合もtrueがかえる
        EXPECT_CALL(*mc, shiftUpNBit(_, _));
    }
    EXPECT_EQ(4, mc->calc(1, 2));

    //モックオブジェクトは勝手に解放されないので、メモリーリークするかもしれないというWarningが出力される
    //表示させたくない場合はMock::AllowLeakを使う
    MOCK::AllowLeak(&mc);
    //モックオブジェクトを初期化する
    Mock::VerifyAndClear(&mc);
    //普通に解放してもよい。
    mc->~MockCalc();
  //delete mc; //こちらでもよい。
}

Windows7のネットワークが異様に遅い問題

こっちにも書いとこう。

      • -

家庭内の共有ファイルアクセスも遅くてこまるし頻繁にネットワークが切断される(というかタイムアウトしてる?)のでどうにかせにゃなーと検索してみた。64bit版でアプリケーション自体の速度は問題ない(ややメモリが使いすぎな感があるが)けどネットワークは本当に遅い。くだりが平均20k、早くても50k…Visual Studio試用版のネットワークインストールが半日たっても終わらない…

チェックサムは、ネットワークを介して転送されるデータの完全性をチェックするシンプルなエラー検出方式です。TCP/IP/UDPなどの通信プロトコルでは、この方式が実装され、受信データがネットワーク上で破損していないかどうかの確認に使用されます。IPv4データグラムの送信元は、データに基づいてチェックサムの値を計算し、それをフレームに埋め込みます。受信側もチェックサムを独自に計算し、その結果に基づいてデータの完全性を確認します。同様に、IPデータグラムのペイロードになるTCP/UDPデータについても、チェックサムが計算され、その値がTCP/UDPフレームに埋め込まれます。
一般に、Fast Ethernetシステムでは、この計算はCPU上で実行されるドライバ・ソフトウェアによって実行されます。しかし、Gigabit Ethernetや10Gbpsの通信速度によるデータ転送では、ソフトウェア・ドライバによるチェックサムの計算はCPUにとって大きな負担になります。このことがホストの最大の課題のひとつであり、アプリケーション処理にまわすCPUサイクルが減少する原因になっています。その結果、ネットワークのフル活用が不可能になり、パフォーマンスが低下してしまうのです。

ということなのだが10Gbpsもあるはずがない家のネットワークではチェックサムオフロード機能はいらんだろう…だいたいデュアルコアなんだからCPUもうちょっと働けむしろ(´∀` )オマエガナーと思ったのでとりあえずIPv6だけ切ってみた。

  1. [コントロールパネル]-[ネットワークと共有センター]-[アダプターの設定の変更]と進んで、ローカルエリア接続の右クリックメニューからプロパティを開く。
  2. ついでなのでインターネットプロトコルバージョン6のチェックをはずして(個人的にはこれはおまじない程度だと思っている)OKののちもう一度同じようにプロパティを開く。
  3. [構成]でネットワークアダプタのプロパティを開いて詳細設定タブをクリック
  4. TCP チェックサムオフロード(IPv6), UDPチェックサムオフロード(IPv6),一括送信オフロード v2(IPv6)をすべて無効にしてOK

ネットワークが一度切断されるけどすぐに再接続される。
転送速度をみると20k->1800k


ちょwwwwwおまwwwwwwwwwwwwwwwww


IPv4のほうもはずしてみたんだけどそしたら900kくらいになったのではずさなくてもいいのかも。XPでははずしてなかったし(というかデフォルトにしていた)Vistaでも問題がない(もちろんデフォルトまま)なので、そこら辺はネットワークカード上のチップとCPUのトレードオフになるあたりなのかも。

IPv6がどうも悪者扱いされているようだが、別に悪いわけじゃないんだけどなぁ。おまじないではなく正しい対処法が広まってほしい。
http://blog.penchi.jp/archives/558.html
http://www.akakagemaru.info/port/windows7ipv6.html

これはネットワークがブツブツ途切れる場合の対処法。ネットワークの切り替えが頻繁に行われるための切断もありうるので、特にブラウジングをしているわけでもないのにネットワークが切断と再接続を繰り返している場合は上記のリンク先の対処法をするのが正しい。

一方でページのロード含め、ネットワーク使用中に切断される場合は、ネットワークの太さに対してデータが大きすぎるために待ち時間が発生していると考えたほうがよい。この場合IPv6を切っても意味がない。なぜならそこが原因ではないからだ。特にブラウジングをしていないときにネットワークが切断される現象が起きないのなら、余計な計算や処理をしているために待ち時間が発生してタイムアウト→切断→再接続になっていると思われる。
のでここで書いてある方法か
http://netserc.blog63.fc2.com/blog-entry-231.html
ここら辺を参考にするのがよいかと。


この記事がもう少しいろんな人に読まれるといいんだがなぁ。

templateのパラメータ引数に制限を設ける

templateはどんな型でも取れちゃうけど取れると困る場合がある。C++0xだとコンセプトっていうのがあるらしいけどC++0xなにそれおいしいの?なので…

実行してからじゃないとわからないようなのだとバグを仕込んでいるのと変わりないので、できるだけコンパイルエラーで検出したいですね。

型はなんでもいいけどスカラかポインタかは区別したい

参照で入れる場合などは注意ということでしょうな。

int main(void){
    int var;
    int* pVar;
    test(&var);
    test(&pVar);
}

class A{
public:
    template<class T> void test(T* p);
}

確かにこれは区別がつかないけど困るな。というわけで制限をかける。
スカラ以外はだめだよという場合は、

template<class T> void test(T* p){//実装する};
template<class T> static inline void test(T**); //実装しない

これは別にメンバ関数でもOK。template static...と一行で書くと怒られるのかな…(うろ覚え(あとで直します

逆にすからはだめで配列だとOKという場合はどうすればいいのだろう?あんまないからいいのか…?

型を制限したいその1(特殊化)

テンプレートの特殊化については以下を参照のこと。
http://www.geocities.jp/ky_webid/cpp/language/037.html
特殊化自体は「この型だけは別の実装で!」とするための手法(型がそんなに多くないならインターフェイスつくって継承先で実装した方がよさげだ)なんだけど、これを使って特定の型だけに制限をかける。

template<class T, class U> struct check_type;
template<class T, class U> void test(T var1, U* var2);
//許可する型の組
template<> struct check_type<int, char*>{};
template<> struct check_type<unsigned int, char*>{};

template<class T, class U> void test(T var1, U* var2){
    //型チェック
    (void)sizeof(check_type<T, U>);
    //実装
};

よく見てないでtest関数を特殊化しようとした馬鹿は僕だけで十分です。
TとUの組で知らないのが出てくるとどのcheck_typeかわからなくてエラーが出るんだねー。これである特定のだけはじけるとかできればいいのになぁ。
これは割と楽でいいんだけど、もっとたくさんある場合は全部書くの大変だし、継承関係あるのなら一気に調べたいという場合はその2へ。

型を制限したいその2
//テンプレートのパラメータ引数に入るはずのクラス
class A{};
class B{};
class A1{};
class B1{};
class A2: public A
{};
class B2: public B
{};

/* C.h */
/* テンプレートメンバ関数を持ったクラス */
#define STATIC_ASSERT(p) typedef int static_assertion_faild[ p ? 1 : -1]

typedef char correct_type;
typedef struct { char dummy2[]; } incorrect_type; //分かりやすいコンパイルエラーを出力

//正しい
correct_type type_check(const volatile A*, const volatile B*);
correct_type type_check(const volatile A1*, const volatile B1*);
//正しいもの以外は全部はじく
incorrect_type type_check(...)

class C
{
...
public:
	template<T, U> void func(T p1, U p2);
}

/* C.cpp */
template<T, U>
void func(T p1, U p2){
	STATIC_ASSERT((sizeof(type_check((T*)0, (U*)0)) == sizeof(correct_type));
	//あとの処理
}

void callFunc(){
    A a;
    B b;
    A1 a1;
    B1 b1;
    A2 a2;
    B2 b2;
    Adummy ad;
    Bdummy bd;

    //コンパイルエラーでない
    func(a, b);
    func(a1, b1);
    func(a2, b2);

  //コンパイルエラー出る
    func(ad, bd);
}

これはかっこいい!
これでcorrect_type以外の組み合わせの場合は弾いてくれる。volatileが付いてると継承クラスまでは許可するのかな。厳密にこれだけとするならvolatileはつけないほうがヨサゲ
http://proger.blog10.fc2.com/blog-entry-20.html
volatileについてはこちら。最適化を抑制するから子クラスからは継承元の公開されてるものは全部見えるので、同じものだよとわかってくれるっつーことか。

特に制限を書いてないけど制限できちゃうよという例

テンプレートパラメータが二つあるとできるぽい。

/* CMyList.h */
template<class T>
class CMyList{
public:
    void copyNum(Func1 func_){ m_func = func_; };
private:
    Func1 m_func;
};

/* Func.h */
class Func1 : public Func
{
public:
    &Func1 operator=(Func1 var){ 
        m_num = var.m_num;
        return *this; 
    };
private:
    int m_num;
}

/* CTest.h */
template<class T, class U> void test(CMyList<T>* list_, U fct);

/* CTest.cpp */
template<class T, class U>
void test(CMyList<T>* list_, U fct){
    list_->copy(fct);
}

/* main */
int main(void){
    CMyList<MyFactor> list;
    Func1 func1;
    Func func
    test(&list, func1);    //OK
    //test(&list, func);   //Compiler error
}

間にテンプレートクラスがあるからかどうかはまた別問題として、テンプレートはビルド時だったかコンパイル時に展開するために、展開先が見つからないとエラーを出してくれる(今までのも全部それでエラーが出る)ので、このTとUの組み合わせが常に決まっているような場合はエラーが出力されます。この場合だとMyListのコピーメソッドのところでFunc1と決定しているのでそれ以外のが来ちゃうとエラーが出る。
こんなバカみたいな設計になんねーからとか思うあなたは正しいと思います。
こういうのはそうなったからラッキーなのであって、基本的には自分でアサーション出させるとかにした方がいいんだろうなぁ。うーむ。