Template Aliases
C++11 Advent Calenderの26日目の記事です。
クリスマスまで残り365日と迫りましたね。C++11 Advent Forever.
さて、C++11で導入された機能の一つがTemplate Aliasesです。元々はTemplate Typedefなどとも呼ばれていました。他の主要な機能と比べて大して目立っていないですが、細かいポイントがいくつかあるような気がします。
Template Aliasesとは?
C言語でもtypedefを使えば型に好きな別名を付けることができます。C++のクラスも型ですからtypedefできます。ではテンプレートクラスはどうかというと、C++03まではそのままの名前で使うしか無かったのです。Template Aliasesならテンプレートに別名を与えることができます。そう、C++11ならね。
template <typename T> using Vec = std::vector<T>; // Template Alias Vec<int> v; // OK: std::vector<int> v; と同じ
あらかじめ引数を当てはめておくこともできます。
// 文字列をキーとする辞書(本当はC++11ならunordered_mapがオススメ) template <typename T> using Dictionary = std::map<std::string, T>; Dictionary<double> dic; // std::map<std::string, double> dic; と同じ
もう一つ例を挙げると、自作のアロケータを簡単に使えるというものがあります。
template <typename T> class MyAllocator { /* ぼくの考えたさいきょうのアロケータ */ }; template <typename T> using MyVector = std::vector<T, MyAllocator<T>>; // アロケータを埋め込む MyVector<int> v; // 指定しなくても上のアロケータを使える
ここまでは割と簡単な例ですが、もっと複雑な型も自在に表現できます。なぜかというとメタプログラミングで作った型を取り出すことができるからです。
#include <type_traits> // constを取り除く std::remove_const<const int>::type x1; // int x1; template <typename T> using remove_const = typename std::remove_const<T>::type; // typenameは必要 remove_const<const int> x2; // int x2;
- typeが要らなくなるだけでも大分格好良くなります。
typedefを置き換える(普通の型のエイリアス)
Template Aliasesはテンプレート引数+エイリアスという形で成り立っているので、エイリアスの部分だけ使用するとtypedefの代わりとして使えます。
typedef int intA_t; // 古いシンタックス(C or C++03) using intB_t = int; // 新しいシンタックス(C++11)
これによって、C言語の邪悪なシンタックス*1から幾分か解放されることになります。
typedef double (*func1A_t)(int); // どれが新しい型名だろう? using func1B_t = double (*)(int); // 新しい型名が分かりやすい using func1C_t = auto (*)(int) -> double; // 戻り値の後置も使ってみる // intを引数に取って、doubleの配列への参照を返す関数へのポインタ typedef double (&(*func2A_t)(int))[100]; // オエーッ using func2B_t = double (&(*)(int))[100]; using func2C_t = auto (*)(int) -> double (&)[100]; // 若干読みやすい?
戻り値の後置については省略*2。配列への参照は昔書いたネタです。
alias declarationによって、typedefはCとの互換性以外の必要性が無くなりました。ナウでヤングなC++11プログラマはusingを使うべきなのです。数十年後typedefは絶滅する運命にあるのです。
変数のエイリアスは作れません
ところでよくある次のようなusing declaration
using std::string;
は、新しく導入されたエイリアスによって
using string = std::string;
とと同じになります。つまり、型のusing declarationはalias declarationの糖衣構文とも考えることができるらしいのです。
しかし、右辺に取れるのは型だけなので、
using std::cout; // OK using Cout = std::cout; // エラー
となって変数では同様の考え方が成り立たないということになります。変数のエイリアスは十分なメリットがないとして導入されていません。
Template Aliasesの特殊化はできません
Template Aliasesは特殊化できません。例えば次のようなコードは不正です:
// 空想のコード template <int> using int_exact; template <> using int_exact<8> = signed char; template <> using int_exact<16> = short; int_exact<16> val; // short val;
しかしクラスの特殊化と組み合わせれば、
// コンパイルできる template <int> struct int_exact_traits; template <> struct int_exact_traits<8> { using type = signed char; }; template <> struct int_exact_traits<16> { using type = short; }; template <int N> using int_exact = typename int_exact_traits<N>::type; // OK int_exact<16> val; // short val; と同じ
このようなコードが書けるので問題ないわけです。Template Aliasesの特殊化が認められていない理由は、クラステンプレートの特殊化・エイリアスの特殊化の2つが入り乱れて混乱することを防ぐためだそうです。
Template Template Parametersに投入する
面白いことに、Template Aliasesはテンプレート実引数にできると標準で定められています。
c++ - Can I use template aliases as template template parameters? - Stack Overflow
これによってTemplate Template Parametersを使う際の問題点が改善されます。
Template Template Parameters - Faith and Brave - C++で遊ぼう
// (型ではなく)テンプレートクラスを引数に取る template <template <typename> class Container> class A { /* ... */ }; template <typename T> using MyVector = std::vector<T, MyAllocator<T>>; // 先ほどの例 A<std::vector> a1; // エラー A<MyVector> a2; // OK!!!
そのままのstd::vectorはテンプレート引数が2つ必要ですから、A
Template Template Parametersの応用というと真っ先にLokiのポリシーが思い浮かびますが、他はパッと思いつかないです。Boostのどこかで使われているかもしれません。
Template Aliasesを継承で置き換えられるか?
Template Aliasesが存在しなかったころにも代替策がいくつかありました。
http://msdn.microsoft.com/ja-jp/library/cc440199%28v=vs.71%29.aspx
- マクロを使ってみる。(ダサい上に問題が多い)
- テンプレートクラスで派生してみる。
- traitsをそのまま利用する。仕方なく::typeを書く。Type Generatorとも言うらしい。
ここで派生に目を向けると、C++11ではコンストラクタを継承できる*3のでより簡単に実現できます。
template <typename T> class MyVector : public std::vector<T> { using Base = std::vector<T>; // ここでもAlias Declaration public: using Base::Base; // コンストラクタの継承 };
いわゆるStrong Typedefと同じで、元の型とは異なる型になります。ただこれだけだと何か足りないかもしれないです。
まとめ
- Template Aliasesによって既存のテンプレートクラスを自在に変形することができます。
- Template Aliasesはテンプレートメタプログラミングのインターフェイスとして活躍するでしょう。
- typedefの代わりにこれからはusingを使いましょう。
- 変数のエイリアスや、Template Aliasesの特殊化は使えません。
- 継承コンストラクタを使えば派生クラスである程度代替ができます。
Template AliasesはGCC 4.7から導入されています。この記事に使用したコンパイラはgcc version 4.7.0 20111217 (experimental)です。
Inheriting Constructorsはまだ実装されていないようです。もうそろそろ実装されると思うのですが…。
参照リンク
まず最初に読むならDr.StroustrupのC++11 FAQが簡潔で分かりやすいです。他の項目も合わせてオススメです。
http://www2.research.att.com/~bs/C++0xFAQ.html#template-alias
詳しい解説は提案に書いてあります。
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1489.pdf
その他色々参考にしました。
GCC-4.7 に Alias declarations (Template aliases) が実装されていた - 野良C++erの雑記帳
Template Aliases すごい - C++でゲームプログラミング
*1:D&E 2.8.1も参照のこと。
*2:C++0x 新たな関数宣言構文 - Faith and Brave - C++で遊ぼうなど。引数に依存した戻り値を書きたいのが元々の動機ですが、スコープを解決できるなど他にも利点があります:http://www2.research.att.com/~bs/C++0xFAQ.html#suffix-return
*3:C++0x 継承コンストラクタ(Inheriting Constructors) - Faith and Brave - C++で遊ぼう
あなたもUbuntu Linuxユーザに(オススメソフト&設定)
パソコンに慣れている人ならLinuxの話を聞いたことくらいはあるだろうが、普段はWindowsを使っている人が大半だろう。Linuxも最近ではかなりユーザに優しくなっていて、日常作業の大半をこなせるようになってきている。
Linuxはサーバや組み込み用途で広く用いられているが、日常作業をこなすデスクトップOSとしてはあまり流行っていない。それでもLinuxで作業する理由はいくつかある。
- APTなどのパッケージ管理が非常に便利
- APTを使うと大抵のソフトはコマンド一行で、または数クリックでインストールできる。インストール済みのソフトも同様に丸ごとアップデートできる。Webサイトからインストーラを探してダウンロードするという工程が必要ないのだ。特にパッケージ管理の恩恵が感じられるのはLaTeXやLAMPなどで複数のソフトを混ぜて使う状況で、依存関係がきちんと管理されているおかげで面倒な設定が必要ない。
- ほとんどウィルスがいない
- Linuxのセキュリティは堅牢で、Windowsと違ってウィルス対策ソフトの必要性が薄いと言われている。これにはオープンソースであること、パッケージが最新に保たれていること、そしてシェアが低いこと、などいくつか理由がある*1。もちろんLinuxのウィルスが存在しないわけではないので、一応ウィルス対策ソフトも用意されている。
- CUI操作が強力
- コマンド操作ができるだけでハッカー気分というのは半分冗談だが、大量のファイルをバッチ処理する場合などにLinuxの強力なシェルが生かせる。また、情報系の勉強をしている人なら、自然とUnix系のコマンドを覚えていけるので非常に有意義だと思う。
- 軽い(?)、安定している
- 他のOSより何となく軽いような気がする。もっとも、UbuntuはLinuxとしてはかなり重量級なのだが…。
- 基本的にタダ
- WindowsだってPCを買うと一緒にバンドルされているから、普通のユーザにとってみればタダのような感覚だ。Linuxがタダで使えることの利点は複数台PCを持っているときに現れる。何らかの事情で古いPCが余ったとき、新たにWindowsを買い足すことなく最新の環境を使うことができる。
私は最近メインPCをWindowsからUbuntu Linuxに移行した。UbuntuはデスクトップLinuxの中でも定評があって、GUIの使いやすさ・ドライバの対応度などが優れている。初心者の方にはまずUbuntuが妥当だと思う。
一方で、一般ユーザがLinuxに乗り換えるには多くの障壁が立ちはだかっている。
- 今まで使用していたソフトが動かない、さらには代替品がない
- 周辺機器にドライバが対応していないことがある
そのため、Windows専用の商用ソフトを多く使用している人、PCゲームが好きな人、特殊な周辺機器をたくさん持っている人などなどにはLinuxは合わないと思う。そういう人にはVMware上での限定的な試用をお薦めしたい。それでもし気に入ったらネイティブにインストールしてみるのもいいと思う。
私はWindowsでもオープンソースソフトしか使っていなかったのでUbuntuへの移行は割とスムーズだった。必要に応じてまたWindowsも使うかもしれないが、Linuxを幅広く使っていくことに変わりはないと思う。
Ubuntuのインストール
現在最新のバージョンはUbuntu 11.10となっている。
Ubuntuをインストールするには、Ubuntu Japanese TeamのサイトからイメージをダウンロードしてCDに書き込んで、CDからPCを起動する。場合によってはBIOSの設定を書き換える必要があるかもしれない。CDドライブやCD-Rが無いならUnetBootinでUSBドライブに書き込んでもいい。
インストール前にHDDのパーティションをLinux用に切り分けておく必要がある。Windows標準の「ディスクの管理」で限界がある場合もEASEUS Partition Masterなどを使えば自由に操作できる。
基本的にインストール中は説明に従って操作していけば正常にインストールできる。ただ操作ミスでHDDのデータが消えてしまうことがあるかもしれないので、心配ならバックアップは取っておく。
Windowsが入っている場合はデュアルブートを選択する場合が多いと思う。少し手間がかかってもいいなら、私としてはWindowsのブートローダからブートする方法をお薦めしたい。この方法なら最初の設定を間違えなければWindowsが起動しなくなることが無い。
taka8aru: WindowsのブートローダーでLinuxとデュアルブートする方法 - Ubuntu 11.04/12.04/12.10, Grub2の場合
上記のサイトではGRUB4DOSでチェインロードする方法を紹介している。Vista/7だと直接GRUB2をロードできる(?)らしく次のサイトの方法でもいい。
Windows 7のブートローダでLinuxのUbuntuとデュアルブートする方法 - MiuxMiu
各種設定 & おすすめソフトウェア
以下の解説はこちらのサイトも参考にした。
http://www.k5.dion.ne.jp/~r-f/sicklylife/memo/ubuntu1110/setting_and_install.html
端末の操作
「端末」(Ctrl+Alt+T)を起動すると、コマンドでの操作ができる。できることなら早いうちからコマンドでの操作に慣れると楽。
必要なソフトウェアはapt-getでインストールできる。慣れないうちは「Ubuntuソフトウェアセンター」を使うのもあり。*2
- sudo apt-get update
- パッケージリストを最新にする
- sudo apt-get upgrade
- インストール済みのパッケージを更新
- sudo apt-get install 〜
- 〜をインストール
Ubuntuをインストールしたばかりならまずアップデートする。
sudo apt-get update sudo apt-get upgrade
フォルダの英語表記
ターミナルを使う場合にホームフォルダの「音楽」といった日本語名はタイプしにくい。次のコマンドを打つと英語表記に戻せる。
LANG=C xdg-user-dirs-gtk-update
出てきたダイアログで"Don't ask me this again"にチェックを入れ"Update Names"をクリックすれば変更される。
Unityの設定
UbuntuのGUIはUnityというものが採用されている。Unityの動作を変更したい時は、UnityのベースとなっているCompizを設定する必要がある。
sudo apt-get install compizconfig-settings-manager
左のランチャが毎回消えるのが嫌なので、消えないようにする。
- 「CompizConfig 設定マネージャ」 を起動(Superを押して"compiz"と入力)
- Ubuntu Unity Plugin を選択
- Behaviour タブの Hide Launcher を Never に
再度ログインすれば設定が反映される。
Webブラウザ : Firefox
Firefoxは標準でインストールされている。プラグインなどもWindows版と同じものが使え、自由にカスタマイズできる。
テキストエディタ : gedit
geditは標準でインストール済みのテキストエディタで、Windowsユーザにも使いやすい。
- バックアップが自動で生成されるようになっているのでこれを解除する。
- 「テキストエディター」(Super + "gedit")を起動して 編集 > 設定 > エディター > 保存する前にバックアップを生成する のチェックを外す。
Vim : GVim
LinuxのテキストエディタにはViとEmacsが有名で、どちらにも熱狂的なファンがたくさんいる。
私が試用した限りではViの方が使いやすいと思ったので、GVimをインストールする。*3
sudo apt-get install vim-gnome
Vimのカスタマイズについてはここでは解説し切れない。私はVim初心者なので、現在~/.vimrcにわずかだけ追加している。
set tabstop=4 set softtabstop=4 set shiftwidth=4 set autoindent set expandtab set wildmode=list,full
日本語入力 : Mozc
MozcはGoogle日本語入力のオープンソース版で、Linuxでも使える。デフォルトのAnthyよりずっと使いやすいのでオススメ。
sudo apt-get install ibus-mozc
右上のバーにIMEのアイコンから、インプットメソッド > インプットメソッドの選択 > 日本語 > Mozcと選択して「追加」をクリックし、Mozcをクリックして「上へ」。
画像編集ソフト : Inkscape , GIMP
InkscapeはIllustratorのようにベクタ画像を編集する場合に、GIMPはPhotoshopのように写真などラスタ画像を編集する場合に使う。どちらも有名で使いやすい。
sudo apt-get install inkscape gimp
MP3タグ編集 : EasyTag
MP3のタグをまとめて編集できる。WindowsでいうとMP3Tagのような感じ。
sudo apt-get install easytag
尚、日本語版だとCDDBで検索する際に強制終了するバグがあるようなので、必要に応じて英語にして起動する。
LANG=C easytag
クラウドストレージ : Ubuntu One , Dropbox , ...
クラウドストレージとは、オンラインにファイルをアップロードし、複数のコンピュータから共有できるサービスのこと。代表的なサービスとしてDropboxやSugarSyncなどがある。
UbuntuにはUbuntu Oneというクラウドストレージがあらかじめインストールされていて、起動して登録すると5GBの容量を無料で使うことができる。Windows、iPhone、Androidなど他OS版も存在する。
DropboxにもLinux版があり.debパッケージになっている。容量は2GB。下のサイトから「Ubuntu (x86 .deb)」をダウンロードしてインストールする。
Wine
Windows用のソフトをネイティブで動かせる。
sudo add-apt-repository ppa:ubuntu-wine/ppa sudo apt-get update sudo apt-get install wine1.3 winecfg
Wine で Office 2007
Wine上でOffice 2007をかなりの再現度で実行できる。Microsoft Officeのシェアは非常に高く、LibreOfficeは互換性が今ひとつなので、どうしても必要になってくる。
- http://appdb.winehq.org/appview.php?iVersionId=4992
- http://www.webupd8.org/2011/01/how-to-install-microsoft-office-2007-in.html
Officeのインストールは色々なサイトで解説されているが、単にOffice 2007を入れるだけなら細かい設定は必要ない。winetricksなどで色々いじってインストールした場合は、Wineサポート対象外であるとはっきりWine公式サイトに書いてある。
インストールする前にWindowsからフォントをコピーしておく。*5"C:\Windows\Fonts"から"~/.wine/drive_c/windows/Fonts"にいくつかコピーする。
- msmincho.ttc , msgothic.ttc
- tahoma.ttc, tahoma.ttf : インストール時の画面を読むために必要
- wingding.ttf : Wordの箇条書きの記号などを表示するために必要
インストールディスクをDVDドライブに入れ、「setup.exe」を右クリックして「Wine Windows Program Loader」で起動すればインストールできる。注意点として、必ず本物のDVDドライブから起動しなければいけないらしい。Ubuntuの書庫マネージャーやアーカイブマウンタは、今のところISOイメージのUDFを読み込めないようだ。
インストール後に起動する前にwinecfgで設定する必要がある。
- ライブラリ > ライブラリの新規オーバーライド に riched20 と打ち込んで、「追加」をクリック。下に出てくるriched20を選択し「編集」から「Native (Windows)」に変更する。
Wine上での日本語IMEの動作は不安定なので、~/.wine/user.regに次の記述を追加する。変換途中の文字列が常に左下に表示されるので見づらいが、ここは表示されないよりはマシだと思うしかない。
[Software\\Wine\\X11 Driver] "InputStyle"="root"
Wineのアンインストール
Wine上でのWindowsアプリのインストールは失敗することが多いので、Wineを丸ごと削除する方法を覚えておいたほうがいい。
FAQ ja - The Official Wine Wiki
まずパッケージを削除する。*6
sudo apt-get --purge autoremove wine
これだけだとWineの設定ファイルは削除されないので、以下のコマンドを実行する。
rm -rf ~/.wine sudo rm -f ~/.config/menus/applications-merged/wine* rm -rf ~/.local/share/applications/wine rm -f ~/.local/share/desktop-directories/wine* rm -f ~/.local/share/icons/????_*.{xpm,png} rm -f ~/.local/share/icons/*-x-wine-*.{xpm,png}
ここまでやっても関連付けが消えないので、適当に自分で削除する。
rm -f ~/.local/share/applications/wine* gvim ~/.local/share/applications/mimeinfo.cache
mimeinfo.cacheからwineが含まれている行を削除する。
さらにWineのリポジトリを削除する場合は、
sudo add-apt-repository -r ppa:ubuntu-wine/ppa
必要に応じて
2chブラウザ : JD
2chブラウザは必要な人だけ。
JDを入れる前に、AAがずれないよう「小夏フォント」「モナーフォント」(MS P ゴシックなどの代わり)などを入れておいた方がいい。
sudo apt-get install ttf-konatu jd
- 初回起動時は「3ペイン表示」を選択
- URLバーにabout:configと入れると詳細な設定ができる(~/.jd/jd.confを編集するのと同じ)
このままだとビットマップフォントで表示されて見づらいので設定する。
Tips - JD for Linux Wiki - JD for Linux - SourceForge.JP
まず~/.font.confに次の内容を入力する。
Konatu false false
端末で次のコマンドを実行する。
fc-cache -fv
理工系向け
大学のレポートや論文などに役立つソフトを中心に。
組版 : LaTeX
LaTeXは書籍や論文を書くのに一般的なツール。
sudo apt-get install texlive texlive-latex-extra ptex-bin okumura-clsfiles sudo apt-get install dvipdfmx dvipsk-ja jmpost jbibtex-bin mendexk sudo apt-get install adobereader-jpn cmap-adobe-japan1
あるいは一行で
sudo apt-get install texlive texlive-latex-extra ptex-bin okumura-clsfiles dvipdfmx dvipsk-ja jmpost jbibtex-bin mendexk adobereader-jpn cmap-adobe-japan1
例えば日本語のPDFを生成する場合は次のように端末に入力する。
platex test.tex && dvipdfmx test.dvi
ちなみにAdobe Readerのメニュー項目が表示されないバグがあるらしく、回避策は以下を参照のこと。
http://linux.ikoinoba.net/index.php?UID=1307549419
数式処理 : Maxima
Maximaはフリーの数式処理システムで、Mathematicaなどと同じようなことができる。複雑な数式を簡略化したり、近似計算せずに微積分・微分方程式・行列などの問題を解いたりできる。
sudo apt-get install wxmaxima
プリント基板 : Eagle
Eagleをインストールしておくと回路図やパターン図を見ることができる。
sudo apt-get install eagle
メモ
- iTunesはまともに使ったことがないので詳しくは分からないが、Bansheeがうまく対応しているかもしれない。
- Evernoteについては良案がない。ChromiumからWebで操作するのが堅実かもしれない。ちなみにNixNote(旧称NeverNote)は非常に重いのでオススメできないし、Windows版EvernoteをWineで動かすのはさらに重い。
- 現在Ubuntu 11.10の書庫マネージャーにバグがあるようで、ISOを解凍するとファイル名の末尾に「;1」が付いてしまう。
- ファイル名だけなら「find . | rename "s/;1//"」で直せるが、それでも正常に展開できるとは限らない。
Suffix Arrayの低速な生成
ふと思い立ってSuffix Arrayを適当に実装することにした。
wikipedia:接尾辞配列
本当はSuffix Array専用の高速な生成方法()があるのだが、今回は適当な実装なのでソートアルゴリズムを使う()。
#include <iostream> #include <iomanip> #include <string> #include <vector> #include <algorithm> template <typename Iterator1, typename Iterator2> bool string_less(Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2) { while (true) { if (first2 == last2) return false; // ? < '\0' == 0 if (first1 == last1) return true; // '\0' < ?(>'\0') == 1 if (*first1 != *first2) return *first1 < *first2; ++first1; ++first2; } } int main() { std::string str("abracadabra"); std::vector<unsigned long> ar; for (unsigned long i = 0; i < str.length(); i++) ar.push_back(i); std::sort(ar.begin(), ar.end(), [&](unsigned long a, unsigned long b)->bool { return string_less(str.begin()+a, str.end(), str.begin()+b, str.end()); } ); for (auto i : ar) { std::cout << std::setw(3) << i << " "; for (auto itr = str.begin()+i; itr != str.end(); itr++) std::cout << *itr; std::cout << std::endl; } }
せっかくなのでC++11の機能を生かそうと思ったのだが、今ひとつ活用出来ていない。気が向いたら高速なものも実装してみようと思う。
GCC 4.6.1をUbuntu 11.04でmake
C++0xの機能を試すためにGCC 4.6が欲しいのだが、UbuntuにはGCC 4.5のパッケージしか用意されていない。こういう時はソースを落としてきてコンパイルすればよい。
GCCのコンパイルには数学関連のライブラリが必要で、それらを先にコンパイルしてインストールしてもよい。しかしmake installするとアンインストールできない事態に陥る。基本的にAPTで全部管理させたいので調べたところ、lib*-devをインストールすればよいことが分かった。
sudo apt-get install libgmp3-dev libmpfr-dev libmpc-dev
で、あとはhttp://gcc.gnu.org/mirrors.htmlからソースを落としてきてmakeするだけと思いきや、
tar xvf gcc-4.6.1.tar.bz2 cd gcc-4.6.1 ./configure make
"asm/errno.h"が見つからないとかいうエラーが出る。最近のUbuntuで生じる問題らしい。
http://am112705.blog.so-net.ne.jp/2011-05-01
とりあえずシンボリックリンクを張る。
sudo ln -s /usr/include/asm-generic /usr/include/asm make
make成功。
ここでmake installするとアンインストールできなくなる。そこで自動的にパッケージを生成してくれるCheckInstallを試したのだが、途中でエラーを吐いて上手くいかない。代わりに試したpacoは使いにくかったので、結局普通にmake installすることになった。
sudo make install
gcc -v
でGCC 4.6.1となれば終了。すぐ終わるかと思ったが意外と手間取った。
boost::tieのネスト
アキラさんの記事を読んでboost::tieのことを思い出し、もしかしてこいつはネストできるのかと気になったので調べてみた。
#include <boost/tuple/tuple.hpp> int main() { using namespace boost; int i; double d; const char* s; tie(tie(i, d), s) = make_tuple(make_tuple(123, 123.4), "abc"); }
残念ながらこのコードはエラーになった。どうやらtieは引数に左辺値を要求しているらしく、内側のtieが返した右辺値を外側のtieが受け取ってエラーになるようだ。
空メンバの最適化をVariadic Templatesで
The "Empty Member" C++ Optimization
これにVariadic Templatesを使ってみようと思いついた。
template <typename Member, typename... Bases> struct BaseOpt : Bases... { Member m; template <typename... Arg> BaseOpt(Arg&&... arg) : m(std::forward<Arg>(arg)...) { } }; class X { static void foo() { } }; class Y { static int bar(int x) { return x; } }; struct Z { Z() : m(123) { } BaseOpt<int, X, Y> m; };
ベースクラスにコンストラクタ引数を与えるのは難しそうだ。そこまでするなら手書きした方が早いかもしれない。