Cry’s Diary

2012-10-31

[]Recursive Function Template Instantiation and New Function Declarator Syntax

以下のコードill-formed である.その理由を述べなさい.

void f()
{}

template<typename T, typename... Types>
auto f(T &&, Types &&... args) -> decltype(f(args...))
{
  return f(args...);
}

int main()
{
  f(0, 1);
}

2012-03-29

[][]GNU coreutils の sort のバージョンが古いために -V (--version-sort) オプションが無いという悲しみの中で,それでも僕たちは前を向いて強く生きていかないといけない.

http://linux.die.net/man/1/sort記述されている -V (--version-sort) オプションに縋って生きてきた僕たちは,ある日,別の環境でこのオプションが使えないことを知って絶望奈落へと突き落とされる.

http://stackoverflow.com/questions/4493205/unix-sort-of-version-numbers

$ curl -s 'http://ftp.tsukuba.wide.ad.jp/software/binutils/' | grep -Eo 'binutils-[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+' | sort -u
binutils-2.10.1
binutils-2.11.2
binutils-2.12.1
binutils-2.13.1
binutils-2.13.2
binutils-2.16.1
binutils-2.19.1
binutils-2.20.1
binutils-2.21.1
binutils-2.8.1
binutils-2.9.1

$ curl -s 'http://ftp.tsukuba.wide.ad.jp/software/binutils/' | grep -Eo 'binutils-[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+' | sort -u -t . -k 1,1n -k 2,2n -k 3,3n
binutils-2.8.1
binutils-2.9.1
binutils-2.10.1
binutils-2.11.2
binutils-2.12.1
binutils-2.13.1
binutils-2.13.2
binutils-2.16.1
binutils-2.19.1
binutils-2.20.1
binutils-2.21.1

[][]最近tar には a (--auto-compress) オプションなるものが追加されたために人類生産性がおよそ1%程度(当社比)向上する.

$ mkdir test

$ tar cavf test.tar.gz test
test/

$ file test.tar.gz
test.tar.gz: gzip compressed data, from Unix, last modified: Thu Mar 29 10:46:53 2012

$ rmdir test/

$ tar xavf test.tar.gz
test/

$ mkdir test

$ tar cavf test.tar.bz2 test
test/

$ file test.tar.bz2
test.tar.bz2: bzip2 compressed data, block size = 900k

$ rmdir test/

$ tar xavf test.tar.bz2
test/

2011-09-20

[][][][]Defining Scoped Enumerations with Human-readable Outputs

出力がちょっとだけホモ・サピエンスに優しい scoped enumeration を定義するだけのカンタンなマクロを作ったような気がする. GCC 4.6.1 -std=c++0x で動いたような気もする.

#include <iostream>

// 第1引数に enumeration の identifier (enum-name) を
// 第2引数以下に enumerator-definition を指定すること.
// 指定できる enumerator-definition は可変長で最大255個(のはず).
CRYOLITE_DECL_ENUM(Color, red, yellow, green, blue, white, black)

int main()
{
  std::cout << Color::red << std::endl;    // => "red"
  std::cout << Color::yellow << std::endl; // => "yellow"
  std::cout << Color::green << std::endl;  // => "green"
  std::cout << Color::blue << std::endl;   // => "blue"
  std::cout << Color::white << std::endl;  // => "white"
  std::cout << Color::black << std::endl;  // => "black"
}

出力がちょっとだけホモ・サピエンスに優しい以外は scoped enumeration とほとんど同じ.「第2引数以下に enumerator-definition を指定すること」って書いてるんだからenumerator-definition のうち constant-expression の部分も書けないといけませんがなぜか書けちゃうようにできてる.ふしぎふしぎ.

#include <iostream>

// usamimi は 178
CRYOLITE_DECL_ENUM(KemonoMimi, inumimi, nekomimi, usamimi = 178, kitsunemimi)

int main()
{
  std::cout << KemonoMimi::inumimi << std::endl;     // => "inumimi"
  std::cout << KemonoMimi::nekomimi << std::endl;    // => "nekomimi"
  std::cout << KemonoMimi::usamimi << std::endl;     // => "usamimi"
  std::cout << KemonoMimi::kitsunemimi << std::endl; // => "kitsunemimi"

  std::cout << static_cast<int>(KemonoMimi::usamimi) << std::endl; // => "178"
}

まー,所詮マクロだし, constant-expression の部分に parenthesized じゃないむき出しの comma があると死にますさようなら.ちなみに上の例と下の例とで enumerator-definition の数を変えて可変長な感じを強調しているつもりだけど微妙に強調できてないっぽいのが悲しいですね? 見た目にこだわって可変長マクロと闘うようなことさえしなければ,実装コードにあるような数字の羅列を書かなくて済むわ, __VA_ARGS__ の展開タイミングに悩まなくて済むわ,いろいろ楽できるものを…….

以下,上記の CRYOLITE_DECL_ENUM というマクロ機能を実現するための実装っぽい何か.これ, GCC 以外でマクロの展開順序という超じゃじゃ馬娘を御しきるのが大変じゃないでしょうか.知らんけど? あ, 'a'-'z', 'A'-'Z' の連続を仮定してるの誰かなんとかしといてください私もう寝ますんで.

続きを読む

2011-09-01

[][][][]Boost.Build @ Linux + GCC + GNU Linker

Boost.Build において,各ターゲットの種類に対してビルドプロパティの値が具体的にどのようなコマンドラインオプション対応するかを, Linux + GCC + GNU Linker の環境において例示するという,私以外の誰も得をしないしそもそも他に理解できる人が居るのかすら怪しい表.(基本コマンド)に各ビルドプロパティ対応するオプションが付加されたものが実際に走るコマンドになる.

featurevalueobj (C++ ソース場合)obj (C ソース場合)lib (built shared) *1lib (built static) *2lib (prebuilt shared) *3lib (prebuilt static) *4exerun
(基本コマンド) "g++" -c -o "target" "source""g++" -x c -c -o "target" "source"*5"ar" rc "target" "sources"*6*7*8
"ranlib" "target"
linkshared-fPIC-fPICN/AN/A
staticN/AN/A
runtime-linkshared
staticN/A (ビルドエラー)-static
runtime-debuggingon
off
optimizationoff-O0-O0
speed-O3-O3
space-Os-Os
profilingoff
on-pg-pg-pg-pg
inliningoff-fno-inline-fno-inline
on-Wno-inline-Wno-inline
full-finline-functions-finline-functions
-Wno-inline -Wno-inline
threadingsingle
multi-pthread-pthread-Wl,-Bdynamic -lrt-Wl,-Bdynamic -lrt
-pthread-pthread
rttion
off-fno-rtti-fno-rtti
exception-handlingon
off
asynch-exceptionsoff
on
extern-c-nothrowoff
on
debug-symbolson-g-g-g-g
off
stripoff
on-Wl,--strip-all-Wl,--strip-all
definevalue-Dvalue-Dvalue
undefvalue
includepath-I"path"-I"path"
cflagsvaluevaluevalue
cxxflagsvaluevalue
fflagsvalue
asmflagsvalue
linkflagsvaluevalue *9value
archiveflagsvaluevalue *10
versionvalue
flagsvalue
location-prefixvalue調査中調査中調査中調査中調査中調査中
usetarget参照
dependencytarget参照
implicit-dependencytarget調査中調査中調査中調査中調査中調査中調査中調査中
warningson-Wall-Wall
all-Wall-Wall
-pedantic-pedantic
off-w-w
warnings-as-errorsoff
on-Werror-Werror
c++-template-depthn-ftemplate-depth-n *11
sourcetarget(参照)(参照)(参照)*12挙動不明挙動不明(参照)(参照)
librarytarget*13※ (同左)挙動不明挙動不明*14
filetargetN/AN/A*15※ (同左)
find-shared-libraryvalue-Wl,-Bdynamic -lvalue-Wl,-Bdynamic -lvalue
find-static-libraryvalue-Wl,-Bstatic -lvalue-Wl,-Bstatic -lvalue
library-pathpath-L"path"-L"path"
namevalueN/AN/A*16*17
tagvalue(参照)(参照)(参照)(参照)調査中調査中(参照)(参照)
searchpathN/AN/A*18*19
locationpath*20※(同左)※(同左)※(同左)※(同左)※(同左)
dll-pathpath-Wl,-R -Wl,"path"-Wl,-R -Wl,"path"LD_LIBRARY_PATH 環境変数path を追加
hardcode-dll-pathstrue*21
false
xdll-pathpath-Wl,-R -Wl,"path" *22LD_LIBRARY_PATH 環境変数path を追加
-Wl,-rpath-link -Wl,"path"
def-filetarget
suppress-import-libfalse
true
allowvalue
address-model(無指定)
32-m32-m32-m32-m32
64-m64-m64-m64-m64
c++abi(無指定)
conditionalvalue参照
buildyes参照
no
user-interfaceconsole
gui
wince
native
auto

特記事項

まー,各バイナリフォーマットの話やリンカ・ローダのお仕事をほとんど把握してないのであれだけど,

*1<link>shared が指定されていて,かつ, <name>value<search>path<file>value も指定されていない場合

*2<link>static が指定されていて,かつ, <name>value<search>path<file>value も指定されていない場合

*3<link>shared が指定されていて,かつ, <name>value<search>path<file>value かのどれか少なくとも一つが指定されている場合

*4<link>static が指定されていて,かつ, <name>value<search>path<file>value かのどれか少なくとも一つが指定されている場合

*5"g++" -o "target" -Wl,-h -Wl,target -shared -Wl,--start-group "sources" -Wl,--end-group

*6:実際の効果に関しては <name>, <search>, <file>記述を参照すること.

*7:実際の効果に関しては <name>, <search>, <file>記述を参照すること.

*8"g++" -o "target" -Wl,--start-group "sources" -Wl,--end-group

*9リンク時のフロントエンドとして g++ が使われるため,指定されたフラグg++コマンドラインオプションとして渡される.フラグをリンカに直接渡したい場合-Wl, を併用すること.

*10arコマンドラインオプションとして渡される.

*111024 までの 32 の倍数,または 1000 までの 10 の倍数が設定できる.

*12:指定されたターゲットのうち, obj (および他の種類のターゲットから暗黙に生成された obj ターゲット) をアーカイブファイルに含める.それ以外の各々のターゲットについては usage-requirements<library>target として追加されるのと同等.さらにすべてのソースに対する <use>requirements に指定されるのと同等.

*13ソースが空でない場合targetソースに追加する.ソースが空の場合挙動不明.

*14ソースが空でない場合targetソースに追加する.ソースが空の場合挙動不明.

*15ライブラリファイルへのフルパスを指定する. <name> と同時に使われることは想定されていない.効果としては usage-requirements<library>"value" および <xdll-path>"dir" が指定されるのと同等.ここで dir<file> で指定されたライブラリファイル存在するディレクトリへのフルパスBoost.Build のドキュメントも参照すること.

*16ライブラリ名 (g++ld-l コマンドラインオプションに与えるのと同じ名前規則による名前) を指定する. <file> と同時に使われることは想定されていない.効果としては usage-requirements<linkflags>"-Wl,-Bdynamic -lvalue" が指定されるのと同等. <search>path と同時に指定された場合usage-requirements<xdll-path>"path" も指定されるのと同等. Boost.Build のドキュメントも参照すること.

*17ライブラリ名 (g++ld-l コマンドラインオプションに与えるのと同じ名前規則による名前) を指定する. <file> と同時に使われることは想定されていない.効果としては usage-requirements<linkflags>"-Wl,-Bstatic -lvalue" が指定されるのと同等. <search>path と同時に指定された場合usage-requirements<xdll-path>"path" も指定されるのと同等. Boost.Build のドキュメントも参照すること.

*18<name>記述を参照すること.

*19<name>記述を参照すること.

*20ターゲットの出力先パスpath に強制される.

*21<hardcode-dll-paths>効果を変化させる.詳細は <hardcode-dll-paths> の項を参照のこと.

*22<hardcode-dll-paths>true が指定されている場合のみ.

FlastFlast 2011/09/03 17:30 boostjpに貼ってください

CryoliteCryolite 2011/09/03 17:46 boostjp のどのセクションが適当ですかね?

2011-07-21

[][][]C++0x の std::unique_lock - std::defer_lock と std::adopt_lock でちょっと高度なロック管理

http://cpplover.blogspot.com/2011/07/mutex.html

C++ソースコード中に「途中のreturnや例外に気をつけること」などといったコメントはあってはならないため,補足.

// 排他的にアクセスするリソース
class exclusive_resource
{
public :
    std::vector<int> v ;
private :
    std::mutex m ;
public :
    void lock() { m.lock() ; }
    void try_lock() { m.try_lock() ; }
    void unlock() { m.unlock() ; }
} ;

exclusive_resource res1, res2 ;

void thread1()
{// res1のみを操作
    std::lock_guard< exclusive_resource > guard( res1 ) ;
    res1.v.push_back(0) ;
}

void thread2()
{// res2のみを操作
    std::lock_guard< exclusive_resource > guard( res2 ) ;
    res2.v.push_back(0) ;
}

void thread3()
{// res1, res2両方を操作
    std::unique_lock<exclusive_resource> lk1(res1, std::defer_lock);
    std::unique_lock<exclusive_resource> lk2(res2, std::defer_lock);
    std::lock( lk1, lk2 ) ; // デッドロックを回避するためstd::lockを使用すること
    // res1, res2両方を操作
    // このスコープをどのように抜けようが res1.unlock() と res2.unlock() が確実に実行される.
}

void thread4()
{// thread3と同じく、res1, res2の両方を操作、thread3とは異なる処理
    std::lock( res1, res2 ) ; // デッドロックを回避するためstd::lockを使用すること
    std::unique_lock<exclusive_resource> lk1(res1, std::adopt_lock);
    std::unique_lock<exclusive_resource> lk2(res2, std::adopt_lock);
    // res1, res2両方を操作
    // このスコープをどのように抜けようが res1.unlock() と res2.unlock() が確実に実行される.
}

std::unique_lock クラステンプレートの基本的な役割,つまりどのような形でスコープを抜けようともロックの解除を確実に行うという RAII のお手本のような役割についてはすでに理解しているものとします

まず最初に補足しておくと, unique_lock操作の対象とする型は std::mutex だけではありません.一般に, lockunlock という名前メンバ関数を持った型――BasicLockable コンセプトのモデル――ならなんでも操作の対象にできます.上のソースコードの例で言えば exclusive_resource クラスはこの要件を満たしているので unique_lock で扱うことができますexclusive_resource クラスを対象にした場合も,当然, unique_lock が果たす基本的な機能は「デストラクタで exclusive_resource クラスオブジェクトunlock メンバ関数を呼び出す」になります

さて, unique_lock には BasicLockable コンセプトのモデルオブジェクトを取るだけの基本的なコンストラクタ以外に,やや特殊なコンストラクタがあります.以下の2つのシグネチャを持つ特殊なコンストラクタが今回説明するものです.

namespace std {
template <class Mutex>
class unique_lock {
public:
typedef Mutex mutex_type;
.....
unique_lock(mutex_type& m, defer_lock_t) noexcept;
unique_lock(mutex_type& m, adopt_lock_t);
.....
}
}

これら2つのコンストラクタの2つ目の引数機能が異なるコンストラクタを呼び分けるための「タグ」を渡すためだけにあります.これらのタグstd::defer_lock_tオブジェクト,および std::adopt_lock_tオブジェクトが <mutex> 標準ヘッダで次のように宣言されているため

namespace std {
constexpr defer_lock_t defer_lock { };
constexpr adopt_lock_t adopt_lock { };
}

これらのコンストラクタ最初に掲げたソースコード中で示したように std::defer_lock オブジェクトおよび std::adopt_lock オブジェクトを用いて呼びだすことができます(これらのタグは, new に対する std::nothrow_t, std::nothrow と同様の機能を果たすものだと説明すれば理解される方もいらっしゃるかもしれません).

1つ目の defer_lock を渡して呼び出す方のコンストラクタですが,これは「unique_lock に対象のオブジェクト管理させるが,コンストラクタの段階ではロックを行わない」というものです. "defer" は「保留する」とか「(実行などを)引き延ばす」などといった意味ですね.作成された unique_lock オブジェクトに対して,後に lock メンバ関数が呼ばれてロックされた状態になることでしょう.従って,最初に掲げたソースコード中のように,複数の unique_lockロックを実行せずに作成しておいて最後std::lock でそれらすべてをデッドロックしないアルゴリズムで安全かつ一斉にロックする,という使い方が可能になります

2つ目の adopt_lock を渡して呼び出す方のコンストラクタですが,これは「すでにロックされた何らかのリソースについて,ロック解放管理unique_lock へ引き継ぐ」という機能を有します.つまり,このコンストラクタすでにロックされたlock メンバ関数が呼び出されていて,かつ, unlock メンバ関数が呼び出されていない)オブジェクトを第1引数に取りコンストラクタの呼び出し時にはロックせず(すでにロックされているオブジェクトが渡されることを前提にしているので当然ですね),以降,ロック解放管理unique_lock に移譲されることになります.このコンストラクタ作成された unique_lock オブジェクトは当然ながらすでにロックされた状態となります.従って,最初に掲げたソースコード中のように, std::lock で複数のリソースロックした後に各々のリソースロック解放管理を行う unique_lock作成する,という使い方が可能になります

このような unique_lock の使い方によって, std::lock を使ってもきちんと RAII を活かしたロック管理が可能になり,ソースコード中に「途中のreturnや例外に気をつけること」などといったコメントを書く必要がなくなります

hito_hpphito_hpp 2011/07/23 17:43 あ、unique_lockを使えばよかったのか。