else節のないifを式でやる

:の片側は適当な式で埋めたconditional-expressionでもいいんだけどこういうのもアリね。

#include <iostream>
 
struct hoge {
    void f() { 
        std::cout << "hoge\n";
    }
};
 
int main() {
    hoge x;
    false && ((void)x.f(), 0); // if (false) { x.f(); }
    std::cout << "-----------------\n";
    true || ((void)x.f(), 0); // Perl とかの unless 相当
}

結果:http://ideone.com/HJIbG
x.f()をvoidにキャストしてるのはx.f()の型がoperator,をオーバーロードしてるかもしれないからです。

Phoenix v3で遊ぶ

日記を書かないと死ぬらしい(ソース不明)ので書きましょう。
Phoenix v3がtrunkにあるということで、前に作ったコードを修正しながら遊んでみました。そういえば前は確かapply作ろうとしたらbindになったとか言いましたが、よく考えたらやっぱりapplyでした。applyにプレースホルダ組み合わせたらbind(apply(), f, a, b…) と似たようなものですね。
というか、Phoenixの関数オブジェクトfはbind(f, …)と同じようなもんだと思えばややこしくない。

#include <boost/config.hpp>

#if defined(BOOST_HAS_TR1_UTILITY) && !defined(BOOST_NO_VARIADIC_TEMPLATES) && !defined(BOOST_NO_DECLTYPE) && !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_DECLTYPE)
# define AVAILABLE_0X_FEATURE 1
#else
# define AVAILABLE_0X_FEATURE 0
#endif

#include <boost/phoenix/core.hpp>
#include <boost/phoenix/operator.hpp>
#include <boost/phoenix/scope.hpp>
#include <boost/phoenix/function.hpp>
#include <boost/phoenix/statement.hpp>
#include <iostream>
#include <string>

#if AVAILABLE_0X_FEATURE
# include <utility>
# include <type_traits>
#else
# include <boost/utility/result_of.hpp>
# include <boost/type_traits/remove_reference.hpp>

# include <boost/preprocessor/arithmetic/inc.hpp>
# include <boost/preprocessor/facilities/intercept.hpp>
# include <boost/preprocessor/facilities/expand.hpp>
# include <boost/preprocessor/repetition/enum_params.hpp>
# include <boost/preprocessor/repetition/enum_shifted_params.hpp>
# include <boost/preprocessor/repetition/repeat.hpp>
# include <boost/preprocessor/repetition/repeat_from_to.hpp>
# include <boost/preprocessor/seq/seq.hpp>
# include <boost/preprocessor/seq/for_each_product.hpp>
# include <boost/preprocessor/seq/for_each_i.hpp>
# include <boost/preprocessor/tuple/rem.hpp>
#endif

namespace bst = boost;

#if AVAILABLE_0X_FEATURE

struct apply_t {
template<typename>
struct result;
template<typename This, typename F, typename ...AS>
struct result<This(F, AS...)> {
typedef decltype(std::declval<F>()(std::declval<AS>()...)) type;
};
template<typename F, typename ...AS>
typename result<apply_t(F &&, AS &&...)>::type
operator()(F && f, AS && ...as) const {
return std::forward<F>(f)(std::forward<AS>(as)...);
}
};

#else

#define DEF_SPECIALIZED_NESTED_RESULT(z, n, data) \
template<typename This, BOOST_PP_ENUM_PARAMS_Z(z, n, typename T)> \
struct result<This(BOOST_PP_ENUM_PARAMS_Z(z, n, T))> { \
typedef typename \
bst::result_of< \
typename bst::remove_reference<T0>::type \
(BOOST_PP_ENUM_SHIFTED_PARAMS_Z(z, n, T))>::type \
type; \
};

#define DEF_APPLY_OVERLOADS_OP(z, n, data) \
BOOST_PP_SEQ_FOR_EACH_PRODUCT(DEF_APPLY_OVERLOADS, \
(((z, n))) BOOST_PP_REPEAT_ ## z(n, MAKE_CONST_SEQ, ~))

#define DEF_APPLY_OVERLOADS(r, seq) \
DEF_APPLY_OVERLOADS_I( \
r, \
BOOST_PP_EXPAND(BOOST_PP_TUPLE_REM(2) BOOST_PP_SEQ_HEAD(seq)), \
BOOST_PP_SEQ_TAIL(seq))
#define DEF_APPLY_OVERLOADS_I(r, zn, seq) DEF_APPLY_OVERLOADS_II(r, zn, seq)
#define DEF_APPLY_OVERLOADS_II(r, z, n, seq) \
template<BOOST_PP_ENUM_PARAMS_Z(z, n, typename T)> \
typename result<apply_t( \
BOOST_PP_SEQ_FOR_EACH_I_R(r, PARAMS_M, \
BOOST_PP_INTERCEPT, seq))>::type \
operator()(BOOST_PP_SEQ_FOR_EACH_I_R(r, PARAMS_M, p, seq)) const \
{ \
return p0(BOOST_PP_ENUM_SHIFTED_PARAMS_Z(z, n, p)); \
}

#define PARAMS_M(r, data, i, elem) \
BOOST_PP_COMMA_IF(i) T ## i elem & data ## i

#define MAKE_CONST_SEQ(z, n, _) )(()(const))(

struct apply_t {
template<typename>
struct result;
BOOST_PP_REPEAT_FROM_TO(1, BOOST_PP_INC(BOOST_PHOENIX_LIMIT), DEF_SPECIALIZED_NESTED_RESULT, ~)
BOOST_PP_REPEAT_FROM_TO(1, BOOST_PP_INC(BOOST_PHOENIX_LIMIT), DEF_APPLY_OVERLOADS_OP, ~)
};

#endif

namespace p3 {
using namespace bst::phoenix;
using namespace bst::phoenix::arg_names;
using namespace bst::phoenix::local_names;
}

p3::function<apply_t> const apply;

template<typename Sig>
struct fptr_adapt_t;

template<typename R, typename A0, typename A1>
struct fptr_adapt_t<R(A0, A1)> {
typedef R result_type;
R operator()(A0 a0, A1 a1) const {
return f(a0, a1);
}
fptr_adapt_t(R (*f)(A0, A1)) : f(f) {}
R (*f)(A0, A1);
};

int f(int x, int y) {return x * y;}

template<typename F>
fptr_adapt_t<F> adapt_function(F * const & f) { return fptr_adapt_t<F>(f); }

p3::function<fptr_adapt_t<int(int, int)> > const ff(adapt_function(&f));

int main () {
using std::cout;
using namespace p3;

int n = 42;

cout << ::apply(_1, n, _2)(&f, 2) << '\n';

let (_a = _1) [cout << ::apply(_a, _2, _3) << '\n'](&f, n, 2);

cout << ff(_1, 2)(3) << '\n';
cout << ff(1, 2)() << '\n';
cout << ff(_1, apply(_2, 3, _3))(2, ff(_1, _2), 4) << '\n';
return 0;
}

新しいswitch statementのご案内

前に http://ideone.com/7NnRj というのを書いて、その後パターンマッチとかできればうれしいなーと思ったので、そんなものを書いた。書いてるうちにぼくのかんがえたさいきょうのぱたーんまっち。という記事が先に上がってたのでこれお蔵入りかなーとか思ったけど、せっかくtraitsで拡張できるようにしたんだし公開しよう、そうしよう、というわけで公開します。ほげー
実際のところはパターンマッチというか、boost::variantっぽいものから中に入っているオブジェクトを取り出そうと試みて、取り出せなかったら次の節を試して、取り出せたらそのオブジェクトをtieで初期化させろみたいにバラす、というのを同時にやるものです。query, unwrap, unpackというtraitsがあって、説明は省略(うまくできない)。まぁcpp -E -Pでもしたあと適当に改行とか入れて読んでください。ちなみに今回はrvalue referenceに対する取り組みはやっていません。考えるのめんどくさくなったので。あとネストした構造に対しては何も考えてません。

namespace arbital { namespace match {

template<typename Tag, typename T, typename = void>
struct query {
template<typename U>
static U & apply(U & v) {
return v;
}
};

template<typename T, typename = void>
struct unwrap {
template<typename U>
static U & apply(U & v) {
return v;
}
};

template<typename Tag, typename T, typename = void>
struct unpack {
template<typename U>
static U & apply(U & v) {
return v;
}
};

}}


#include <boost/variant/variant_fwd.hpp>
#include <boost/variant/get.hpp>
#include <boost/optional/optional.hpp>
#include <boost/none.hpp>

namespace arbital { namespace match {

template<typename Tag, BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct query<Tag, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > {
template<typename U>
static auto apply(U & v)->
boost::optional<decltype(*boost::get<Tag>(&v)) &>
{
if (auto chosen = boost::get<Tag>(&v)) {
return boost::optional<decltype(*chosen) &>(*chosen);
} else {
return boost::none;
}
}
};

}}


#include <boost/optional/optional.hpp>

namespace arbital { namespace match {

template<typename T>
struct unwrap<boost::optional<T> > {
template<typename U>
static auto apply(U & v)->decltype(boost::get(v)) {
return boost::get(v);
}
};

}}


#include <boost/fusion/support/category_of.hpp> // is_random_access
#include <boost/fusion/support/is_sequence.hpp>
#include <boost/fusion/container/vector/vector_fwd.hpp>
#include <boost/fusion/sequence/intrinsic/at.hpp>

#include <boost/utility/enable_if.hpp>
#include <boost/mpl/and.hpp>
#include <boost/mpl/or.hpp>

namespace arbital { namespace match {

template<typename N, typename T>
struct unpack<N, T,
typename boost::enable_if<
boost::mpl::and_<boost::fusion::traits::is_sequence<T>,
boost::fusion::traits::is_random_access<T> > >::type>
{
template<typename U>
static auto apply(U & v)->
decltype(boost::fusion::at<N>(v))
{
return boost::fusion::at<N>(v);
}
};

}}


#include <boost/preprocessor/control/iif.hpp>
#include <boost/preprocessor/logical/not.hpp>
#include <boost/preprocessor/arithmetic/sub.hpp>
#include <boost/preprocessor/repetition/enum_trailing_params.hpp>
#include <boost/preprocessor/facilities/intercept.hpp>
#include <boost/preprocessor/punctuation/paren.hpp>
#include <boost/preprocessor/punctuation/comma.hpp>

#define ARBITAL_PP_TUPLE_SIZE(tuple) \
ARBITAL_PP_TUPLE_SIZE_I(ARBITAL_PP_TUPLE_REM tuple ARBITAL_PP_TUPLE_SIZE_TABLE)
#define ARBITAL_PP_TUPLE_SIZE_I(x) ARBITAL_PP_TUPLE_HEAD((ARBITAL_PP_TUPLE_DROP_255(x)))

#define ARBITAL_PP_TUPLE_ELEM(n, tuple) \
ARBITAL_PP_TUPLE_ELEM_I( \
BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PP_SUB(255, n), \
BOOST_PP_INTERCEPT) \
ARBITAL_PP_TUPLE_REM tuple)
#define ARBITAL_PP_TUPLE_ELEM_I(x) ARBITAL_PP_TUPLE_HEAD((ARBITAL_PP_TUPLE_DROP_255(x)))

#define ARBITAL_PP_TUPLE_REM(...) __VA_ARGS__

#define ARBITAL_PP_TUPLE_EAT(...)

#define ARBITAL_PP_TUPLE_HEAD(tup) \
ARBITAL_PP_TUPLE_HEAD_I tup
#define ARBITAL_PP_TUPLE_HEAD_I(...) \
ARBITAL_PP_TUPLE_HEAD_II(__VA_ARGS__,)
#define ARBITAL_PP_TUPLE_HEAD_II(_1,...) _1

#define ARBITAL_PP_TUPLE_TAIL(tup) \
ARBITAL_PP_TUPLE_TAIL_I tup
#define ARBITAL_PP_TUPLE_TAIL_I(...) \
ARBITAL_PP_TUPLE_TAIL_II(__VA_ARGS__ ARBITAL_PP_TUPLE_EAT BOOST_PP_LPAREN() , BOOST_PP_RPAREN())
#define ARBITAL_PP_TUPLE_TAIL_II(_1,...) (__VA_ARGS__)

#define ARBITAL_PP_TUPLE_TAKE(n, tuple) \
ARBITAL_PP_TUPLE_TAKE_III( \
BOOST_PP_IIF(BOOST_PP_NOT(n), \
() ARBITAL_PP_TUPLE_EAT, \
ARBITAL_PP_TUPLE_TAKE_I)(n, tuple))
#define ARBITAL_PP_TUPLE_TAKE_I(n, tuple) \
ARBITAL_PP_TUPLE_TAKE_II( \
BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PP_SUB(255, n), \
BOOST_PP_INTERCEPT), \
ARBITAL_PP_TUPLE_REM tuple)
#define ARBITAL_PP_TUPLE_TAKE_II(commas, tuple) \
(ARBITAL_PP_TUPLE_TAKE_255(ARBITAL_PP_TUPLE_EAT BOOST_PP_LPAREN() commas BOOST_PP_RPAREN() tuple))
#define ARBITAL_PP_TUPLE_TAKE_III(res) ARBITAL_PP_TUPLE_TAKE_IV(res)
#define ARBITAL_PP_TUPLE_TAKE_IV(res) res

#define ARBITAL_PP_TUPLE_DROP_255( \
_1,_2,_3,_4,_5,_6,_7,_8,_9,_10, \
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
_61,_62,_63,_64,_65,_66,_67,_68,_69,_70, \
_71,_72,_73,_74,_75,_76,_77,_78,_79,_80, \
_81,_82,_83,_84,_85,_86,_87,_88,_89,_90, \
_91,_92,_93,_94,_95,_96,_97,_98,_99,_100, \
_101,_102,_103,_104,_105,_106,_107,_108,_109,_110, \
_111,_112,_113,_114,_115,_116,_117,_118,_119,_120, \
_121,_122,_123,_124,_125,_126,_127,_128,_129,_130, \
_131,_132,_133,_134,_135,_136,_137,_138,_139,_140, \
_141,_142,_143,_144,_145,_146,_147,_148,_149,_150, \
_151,_152,_153,_154,_155,_156,_157,_158,_159,_160, \
_161,_162,_163,_164,_165,_166,_167,_168,_169,_170, \
_171,_172,_173,_174,_175,_176,_177,_178,_179,_180, \
_181,_182,_183,_184,_185,_186,_187,_188,_189,_190, \
_191,_192,_193,_194,_195,_196,_197,_198,_199,_200, \
_201,_202,_203,_204,_205,_206,_207,_208,_209,_210, \
_211,_212,_213,_214,_215,_216,_217,_218,_219,_220, \
_221,_222,_223,_224,_225,_226,_227,_228,_229,_230, \
_231,_232,_233,_234,_235,_236,_237,_238,_239,_240, \
_241,_242,_243,_244,_245,_246,_247,_248,_249,_250, \
_251,_252,_253,_254,_255,...) \
__VA_ARGS__

#define ARBITAL_PP_TUPLE_TAKE_255( \
_1,_2,_3,_4,_5,_6,_7,_8,_9,_10, \
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
_61,_62,_63,_64,_65,_66,_67,_68,_69,_70, \
_71,_72,_73,_74,_75,_76,_77,_78,_79,_80, \
_81,_82,_83,_84,_85,_86,_87,_88,_89,_90, \
_91,_92,_93,_94,_95,_96,_97,_98,_99,_100, \
_101,_102,_103,_104,_105,_106,_107,_108,_109,_110, \
_111,_112,_113,_114,_115,_116,_117,_118,_119,_120, \
_121,_122,_123,_124,_125,_126,_127,_128,_129,_130, \
_131,_132,_133,_134,_135,_136,_137,_138,_139,_140, \
_141,_142,_143,_144,_145,_146,_147,_148,_149,_150, \
_151,_152,_153,_154,_155,_156,_157,_158,_159,_160, \
_161,_162,_163,_164,_165,_166,_167,_168,_169,_170, \
_171,_172,_173,_174,_175,_176,_177,_178,_179,_180, \
_181,_182,_183,_184,_185,_186,_187,_188,_189,_190, \
_191,_192,_193,_194,_195,_196,_197,_198,_199,_200, \
_201,_202,_203,_204,_205,_206,_207,_208,_209,_210, \
_211,_212,_213,_214,_215,_216,_217,_218,_219,_220, \
_221,_222,_223,_224,_225,_226,_227,_228,_229,_230, \
_231,_232,_233,_234,_235,_236,_237,_238,_239,_240, \
_241,_242,_243,_244,_245,_246,_247,_248,_249,_250, \
_251,_252,_253,_254,_255,...) \
_1,_2,_3,_4,_5,_6,_7,_8,_9,_10, \
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
_61,_62,_63,_64,_65,_66,_67,_68,_69,_70, \
_71,_72,_73,_74,_75,_76,_77,_78,_79,_80, \
_81,_82,_83,_84,_85,_86,_87,_88,_89,_90, \
_91,_92,_93,_94,_95,_96,_97,_98,_99,_100, \
_101,_102,_103,_104,_105,_106,_107,_108,_109,_110, \
_111,_112,_113,_114,_115,_116,_117,_118,_119,_120, \
_121,_122,_123,_124,_125,_126,_127,_128,_129,_130, \
_131,_132,_133,_134,_135,_136,_137,_138,_139,_140, \
_141,_142,_143,_144,_145,_146,_147,_148,_149,_150, \
_151,_152,_153,_154,_155,_156,_157,_158,_159,_160, \
_161,_162,_163,_164,_165,_166,_167,_168,_169,_170, \
_171,_172,_173,_174,_175,_176,_177,_178,_179,_180, \
_181,_182,_183,_184,_185,_186,_187,_188,_189,_190, \
_191,_192,_193,_194,_195,_196,_197,_198,_199,_200, \
_201,_202,_203,_204,_205,_206,_207,_208,_209,_210, \
_211,_212,_213,_214,_215,_216,_217,_218,_219,_220, \
_221,_222,_223,_224,_225,_226,_227,_228,_229,_230, \
_231,_232,_233,_234,_235,_236,_237,_238,_239,_240, \
_241,_242,_243,_244,_245,_246,_247,_248,_249,_250, \
_251,_252,_253,_254,_255

#define ARBITAL_PP_TUPLE_SIZE_TABLE 256,255,254,253,252,251, \
250,249,248,247,246,245,244,243,242,241, \
240,239,238,237,236,235,234,233,232,231, \
230,229,228,227,226,225,224,223,222,221, \
220,219,218,217,216,215,214,213,212,211, \
210,209,208,207,206,205,204,203,202,201, \
200,199,198,197,196,195,194,193,192,191, \
190,189,188,187,186,185,184,183,182,181, \
180,179,178,177,176,175,174,173,172,171, \
170,169,168,167,166,165,164,163,162,161, \
160,159,158,157,156,155,154,153,152,151, \
150,149,148,147,146,145,144,143,142,141, \
140,139,138,137,136,135,134,133,132,131, \
130,129,128,127,126,125,124,123,122,121, \
120,119,118,117,116,115,114,113,112,111, \
110,109,108,107,106,105,104,103,102,101, \
100,99,98,97,96,95,94,93,92,91, \
90,89,88,87,86,85,84,83,82,81, \
80,79,78,77,76,75,74,73,72,71, \
70,69,68,67,66,65,64,63,62,61, \
60,59,58,57,56,55,54,53,52,51, \
50,49,48,47,46,45,44,43,42,41, \
40,39,38,37,36,35,34,33,32,31, \
30,29,28,27,26,25,24,23,22,21, \
20,19,18,17,16,15,14,13,12,11, \
10,9,8,7,6,5,4,3,2,1,



#include <type_traits>

#include <boost/mpl/size_t.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/preprocessor/facilities/is_empty.hpp>
#include <boost/preprocessor/control/iif.hpp>
#include <boost/preprocessor/arithmetic/dec.hpp>

#define ARBITAL_SWITCH_DEFINE_EXPR_FUN(name_sig, body) \
auto name_sig->decltype body \
{ return body; }

namespace arbital { namespace match {

namespace _call {

template<typename Tag, typename T>
ARBITAL_SWITCH_DEFINE_EXPR_FUN(
query(T & v),
(match::query<Tag, typename std::remove_cv<T>::type>::apply(v)))

template<typename T>
ARBITAL_SWITCH_DEFINE_EXPR_FUN(
unwrap(T & v),
(match::unwrap<typename std::remove_cv<T>::type>::apply(v)))

template<typename Tag, typename T>
ARBITAL_SWITCH_DEFINE_EXPR_FUN(
unpack(T & v),
(match::unpack<Tag, typename std::remove_cv<T>::type>::apply(v)))

template<size_t N, typename T>
ARBITAL_SWITCH_DEFINE_EXPR_FUN(
unpack(T & v),
(_call::unpack<boost::mpl::size_t<N> >(v)))

}

}}

#undef ARBITAL_SWITCH_DEFINE_EXPR_FUN

#define ARBITAL_SWITCH(...) \
if (bool _switch_cond_ = true) \
for (auto && _switch_var_ = (__VA_ARGS__); \
_switch_cond_; \
_switch_cond_ = false) \
if (0) {}

#define ARBITAL_CASE(...) \
else if (_switch_var_ == (__VA_ARGS__))

#define ARBITAL_DEFAULT else

#define ARBITAL_MATCH(...) \
ARBITAL_MATCH_I)((__VA_ARGS__))(
#define ARBITAL_MATCH_I(tup) \
ARBITAL_MATCH_II(BOOST_PP_DEC(ARBITAL_PP_TUPLE_SIZE(tup)), tup)
#define ARBITAL_MATCH_II(n, tup) \
ARBITAL_MATCH_III(ARBITAL_PP_TUPLE_TAKE(n, tup), ARBITAL_PP_TUPLE_ELEM(n, tup))
#define ARBITAL_MATCH_III(tag, vars) \
else if (auto && _query_var_ = ::arbital::match::_call::query<ARBITAL_PP_TUPLE_REM tag>(_switch_var_)) \
for (auto && _match_var_ = ::arbital::match::_call::unwrap(_query_var_); \
_switch_cond_; \
_switch_cond_ = false) \
ARBITAL_SWITCH_UNPACK_TUPLE(_match_var_, vars)

#define ARBITAL_SWITCH_UNPACK_TUPLE(packed, vars) \
BOOST_PP_REPEAT(ARBITAL_PP_TUPLE_SIZE(vars), ARBITAL_SWITCH_UNPACK_TUPLE_M, (packed, vars))

#define ARBITAL_SWITCH_UNPACK_TUPLE_M(z, n, data) \
ARBITAL_SWITCH_UNPACK_TUPLE_M_I(n, ARBITAL_PP_TUPLE_REM data)
#define ARBITAL_SWITCH_UNPACK_TUPLE_M_I(n, x) \
ARBITAL_SWITCH_UNPACK_TUPLE_M_II(n, x)
#define ARBITAL_SWITCH_UNPACK_TUPLE_M_II(n, packed, vars) \
BOOST_PP_IIF(BOOST_PP_IS_EMPTY(ARBITAL_PP_TUPLE_ELEM(n, vars)), \
ARBITAL_PP_TUPLE_EAT, \
ARBITAL_SWITCH_UNPACK_TUPLE_M_III) \
(n, packed, ARBITAL_PP_TUPLE_ELEM(n, vars))
#define ARBITAL_SWITCH_UNPACK_TUPLE_M_III(n, packed, var) \
for (auto & var = ::arbital::match::_call::unpack<n>(packed); _switch_cond_; _switch_cond_ = false)



#include <iostream>
#include <string>

#include <boost/variant/variant.hpp>
#include <boost/fusion/container/vector/vector.hpp>
#include <boost/mpl/print.hpp>

void print() { std::cout << '\n'; }

template<typename T, typename ...U>
void print(T && x, U && ...xs) {
std::cout << std::forward<T>(x);
::print(std::forward<U>(xs)...);
}

int main() {
char x = 'x';
ARBITAL_SWITCH (x)
ARBITAL_CASE ('a') {
print("'a'");
} ARBITAL_CASE ('b') print("'b'");
ARBITAL_CASE (x) {
print("x");
} ARBITAL_DEFAULT {
print("other");
}

namespace bst = ::boost;
namespace fu = bst::fusion;

boost::variant<
int,
fu::vector<int, std::string> >
v = fu::vector<int, std::string>(1, "hogehoge");

ARBITAL_SWITCH (v)
ARBITAL_MATCH (int, (n)) {
print("int: n = ", n);
}
ARBITAL_MATCH (fu::vector<int, std::string>, (n, str)) {
print("(int, string) : n = ", n, ", str = ", str);
}
}

したいかどうかは別として、caseとmatchは混ぜて使うことができます。

プリプロセス時足し算・引き算・かけ算・剰余演算を定数時間で

http://ideone.com/eK4vc

#include <boost/preprocessor/cat.hpp>
 
#define PP_ADD_C(x, y) PP_NAT_TO_LIT(PP_NAT(x) PP_NAT(y))
 
#define PP_SUB_C(x, y) PP_COMPL(PP_ADD_C(PP_COMPL(x), y))
 
#define PP_MUL_C(x, y) PP_NAT_TO_LIT(PP_CST_REPEAT(x, PP_NAT(y)))
 
#define PP_MOD_C(x, y) \
    PP_CST_ELEM_16(PP_NAT(x) PP_MOD_MAKE_MOD_TABLE(y))
 
/**
 * m-1,m-2...,0の繰り返しを作って、CST_ELEM_16で0が来るように先頭に16%m+1個要素を追加
 *
 * PP_CST_DROP_16(PP_NAT(PP_SUB_C(m,1)) NAT_TABLE)   必要なオフセット
 * の繰り返しのF番目まで
 * 2,1,0,2,1,0,2,1,0,2,1,0,2,1,0,2,1,                16%3 + 1
 * 3,2,1,0,3,2,1,0,3,2,1,0,3,2,1,0,3,                16%4 + 1
 * 4,3,2,1,0,4,3,2,1,0,4,3,2,1,0,4,3,                16%5 + 1
 * 5,4,3,2,1,0,5,4,3,2,1,0,5,4,3,2,1,                16%6 + 1
 * 6,5,4,3,2,1,0,6,5,4,3,2,1,0,6,5,4,                16%7 + 1
 * 7,6,5,4,3,2,1,0,7,6,5,4,3,2,1,0,7,                16%8 + 1
*/
#define PP_MOD_MAKE_MOD_TABLE(m) \
    PP_CST_DROP_16(PP_NAT(PP_REM_OF_DIV_16(m)) NAT_TABLE) \
    PP_CST_REPEAT(16, PP_CST_DROP_16(PP_NAT(PP_SUB_C(m,1)) NAT_TABLE))
 
#define PP_COMPL(n) PP_NAT_TO_COMPL(PP_NAT(n))
 
#define PP_NAT_TO_LIT(...) PP_CST_ELEM_16(__VA_ARGS__ NAT_TABLE)
#define PP_NAT_TO_COMPL(...) PP_CST_ELEM_16(__VA_ARGS__ COMPL_TABLE)
 
#define PP_REM_OF_DIV_16(x) PP_CST_ELEM_16(PP_NAT(x) REM_TABLE)
 
#define NAT_TABLE 16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,
#define COMPL_TABLE 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
#define REM_TABLE 0,1,2,3,4,5,6,7,0,2,4,1,0,1,0,0,ERROR,
 
#define PP_NAT(n) PP_NAT_I(n)
#define PP_NAT_I(n) PP_NAT_ ## n
 
#define PP_NAT_0 
#define PP_NAT_1 ,
#define PP_NAT_2 ,,
#define PP_NAT_3 ,,,
#define PP_NAT_4 ,,,,
#define PP_NAT_5 ,,,,,
#define PP_NAT_6 ,,,,,,
#define PP_NAT_7 ,,,,,,,
#define PP_NAT_8 ,,,,,,,,
#define PP_NAT_9 ,,,,,,,,,
#define PP_NAT_10 ,,,,,,,,,,
#define PP_NAT_11 ,,,,,,,,,,,
#define PP_NAT_12 ,,,,,,,,,,,,
#define PP_NAT_13 ,,,,,,,,,,,,,
#define PP_NAT_14 ,,,,,,,,,,,,,,
#define PP_NAT_15 ,,,,,,,,,,,,,,,
#define PP_NAT_16 ,,,,,,,,,,,,,,,,
 
// tuple operations
#define PP_TUPLE_REM(...) __VA_ARGS__
 
// comma-separated-tokens operations
#define PP_CST_ELEM_16(...) PP_CST_HEAD(PP_CST_DROP_16(__VA_ARGS__))
 
#define PP_CST_HEAD(...) PP_CST_HEAD_I(__VA_ARGS__)
#define PP_CST_HEAD_I(_0,...) _0
 
#define PP_CST_DROP_16(...) PP_CST_DROP_16_I(__VA_ARGS__)
#define PP_CST_DROP_16_I(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_a,_b,_c,_d,_e,_f,...) __VA_ARGS__
 
#define PP_CST_REPEAT(m, ...) PP_CST_REPEAT_I(m, (__VA_ARGS__))
#define PP_CST_REPEAT_I(m, x) PP_CST_REPEAT_ ## m(PP_TUPLE_REM x)
// PP_CST_REPEAT_n で __VA_ARGS__ を繰り返すのがめんどくさいので
// 1トークン列として認識させる
 
#define PP_CST_REPEAT_0(x)
#define PP_CST_REPEAT_1(x) x 
#define PP_CST_REPEAT_2(x) x x
#define PP_CST_REPEAT_3(x) x x x
#define PP_CST_REPEAT_4(x) x x x x
#define PP_CST_REPEAT_5(x) x x x x x
#define PP_CST_REPEAT_6(x) x x x x x x
#define PP_CST_REPEAT_7(x) x x x x x x x
#define PP_CST_REPEAT_8(x) x x x x x x x x
#define PP_CST_REPEAT_9(x) x x x x x x x x x
#define PP_CST_REPEAT_10(x) x x x x x x x x x x
#define PP_CST_REPEAT_11(x) x x x x x x x x x x x
#define PP_CST_REPEAT_12(x) x x x x x x x x x x x x
#define PP_CST_REPEAT_13(x) x x x x x x x x x x x x x
#define PP_CST_REPEAT_14(x) x x x x x x x x x x x x x x
#define PP_CST_REPEAT_15(x) x x x x x x x x x x x x x x x
#define PP_CST_REPEAT_16(x) x x x x x x x x x x x x x x x x
 
 
#include <iostream>
 
int main() {
    std::cout << PP_ADD_C(PP_MUL_C(1,3),5) << '\n';
    std::cout << PP_SUB_C(PP_ADD_C(7,4),6) << '\n';
    std::cout << PP_MUL_C(3,PP_MOD_C(14,6)) << '\n';
}

ループを回さない、テーブルを大きくしすぎない、あたりを目標に作ってみました。割り算は無理でした。割り算難しい。
まぁここまでやるならテーブルを二段構えに、つまり16のカンマ区切りテーブルを16個カンマで区切って九九表ならぬ十六十六表作ってもいいのかも知れませんが。

fontconfigの設定(1)

fontconfigの設定ぐらい手打ちでできないと人間として認められないそうなので、がんばって調べてみました。しかし折角人間と認められても、数ヶ月後には再び人間でない何かになってしまいそうなので、未来の自分も人間と認められ続けるべく、ここに記録を残しておきます。nヶ月後の私も、どうかこれを見て人間を続けられるように頑張ってください。もっとも調べたと言っても9割方はmanの情報です。

最初にfontconfigの基本的な事項を解説し、それを元にフォントを決定するまでの大まかな流れを示します。その後、設定ファイル(XML)の各要素について、擬似的なプログラミング言語を用いた処理を交えながら解説します。
かなり内容が多くなってしまいましたので、今回のこの記事では、基本的な事項について解説します。

フォント

このシリーズの記事で言う「フォント」とは、「字形情報のセット」という意味です。「フォント名」「フォントの名前」は「字形情報のセットに付けられた名前」です。「フォントファイル」は「字形情報のセットが格納されているファイル」です。一応本文中に出てくるこれらの言葉は、ここに挙げた意味通りに使っているつもりですが、もしかしたらそうでないこともあるかも知れません。ごめんなさい。

font name

"name" とは言いますが、これは「IPA ゴシック-8:bold:antialias=true」のように、フォントの名前以外に大きさや太さその他のオプションまで含めることができます(含めなくてもいいです)。Xftに対応しているアプリケーションなら、.Xresourcesなどでフォントや大きさやその他もろもろを指定するとき、この書式で指定できます。font nameに含まれている、フォントの名前、大きさその他の色々な項目は、プロパティといいます。一般的に表わすと「<family>-<size>:<propety1>=<value11>,<value12>…:<property2>=<value21>,<value22>…:…」という感じです。フォント名も、familyというプロパティです。いくつかのプロパティのいくつかの値については省略記法が用意されていて、「bold」や「weight=bold」は、「weight=200」と同じ意味になります。
一つのプロパティに対して複数の値を指定できます。指定した順に優先度が高い要求となります。要するに本命要求以外の代替案を付けられるということです。font nameで表わすと「IPA ゴシック-9:width=thin,normal,bold」と書きます。この場合、thinがいいけどなかったらnormalでもいいよ、それもなかったらboldで、みたいな感じです。familyも複数指定できて、「IPA ゴシック-9:family=M+2P+IPAG,sans-serif」とすればIPA ゴシックがなければM+2P+IPAGが、それもなければsans-serifが選ばれます。sizeも同様にIPAG ゴシック-9:size=12,10,15みたいな指定ができます。別に連続した数値である必要はないですし、昇順、降順になっている必要もありません。自分が優先したい順に並べてください。
先にでてきた例の"sans-serif"というのを見れば分かるように、このfamily名というのは特定のフォント名であるとは限らないです。fontconfigの設定ファイルで、いくつかのフォント名をセットにして一つの名前を付けることができます。sans-serifはもちろんゴシック体フォントの集合に対する名前で、要するに、「とにかく何かゴシック体のやつで」と言っているわけです。

pattern

font nameの抽象表現がpatternです。というか、patternを文字列で表現したものがfont nameです。
システムにインストールされているフォントも全てpatternで表現することができます。ここでちょっとポイントですが、例えばTimesがインストールされているなら、8ptで普通の太さ傾きなしで名前がTimesというpatternと、8ptで太字傾きなしで(略)と、8ptで普通の太さ斜体で(略)と、8ptで太字斜体で(略)と、9ptで(略)と、…というpatternが全てインストールされている、という考えかたをします。もちろんプロパティはここに挙げた以外にもいっぱいあるので、それら全ての組み合わせ分だけpatternがあることになります。fontconfigは、このインストールされたpatternの中から、要求されたpatternに最も近いものを選びます。

fontconfig設定ファイルの概要

fontconfigの設定ファイルは、定められたDTDに従っている妥当なXML文書である必要があります。正直言ってXMLという時点で人間が読み書きするには不便なフォーマットですが、そこに文句を言っても始まらないのでやめておきます。このDTDを記述しているファイルは、システムのどこかに置いてあるでしょう。ArchLinuxの場合は/etc/fonts.d/fonts.dtdがそれでした。fonts.dtdはコメントで注釈を付けてくれてますので、これも書き方のヒントになるかと思います。
設定ファイルはいくつかに分割することができます。その場合も、一つ一つのファイルは妥当なXML文書でないといけません。デフォルトの状態で大本の設定ファイルである/etc/fonts.d/fonts.confに、~/.font.confと.font.conf.dを読みこむように書いてあるので、それらのファイルに設定を書く、またはディレクトリ下に設定ファイルを置くなどすれば、読まれます。

fontconfigがフォントを決定する流れ

fontconfigは、所望するpatternを受け取り、そのpatternを各<match target="pattern">要素の内容に従って修正します。
それから、修正したpatternに一番近いpatternを、システム内で見つかる全patternから選びます。この「近さ」を測定するためのルールについては、そんなに気にしなくても多分大丈夫です。詳しくはmanでも読んでください。
最後に、選ばれたpatternを、今度は各<match target="font">要素の内容に従って修正します。こうしてできたpatternが示すフォントを、最終的なフォントとして返します。

Unicode, UCS-2/4, UTF-8/16/32についての整理

※注意:これは私が調べた結果をまとめたものなので、間違いがあれば指摘していただけるとありがたいです。

用語

ここで整理したいことについて話せるようにするための説明なので、正確ではないです(符号化文字集合とか符号点とか)。

文字集合
文字の集合
符号化文字集合
文字と負ではない整数(または整数列)の対応表。その整数が、コンピュータで扱うビットの並びそのものとは限らない。コンピュータでは、この整数を符号化方式によって変換したものを扱う。
符号点、符号位置、コードポイント
符号化文字集合で、文字に対応している整数(または整数列)のこと。「符号位置」はUnicodeでの呼び方。
符号化方式
符号点を、コンピュータで扱うビット列で表現するための変換方式。よく「エンコーディング」と呼ばれるものはこちら。符号化符号化うるさいので、ここでは「エンコーディング」ということにする。

※「符号化文字集合」と「符号化方式」が指す「符号化」の意味は多分違う。前者のそれは文字に番号(符号)を振ったことを言い、後者は符号をコンピュータが扱うためのビット列に変換することを言うと思う。

UnicodeとUCS

Unicodeとは符号化文字集合の名前であり、UCSは符号化文字集合の規格である。UCSでは、UCS-4とそのサブセットであるUCS-2の2種類の符号化文字集合が定められている。
Unicodeはもともと16ビットで表現した符号空間に文字を割り当てていたが、足りなくなったので後に21ビットに拡張した。
UCSは、31ビットで表現される符号化文字集合で、Unicodeとは別に作られていたが、最終的に当時16ビット空間であったUnicodeをまるまる取り込むことになった(このため下記のような互換性が発生している)。この16ビットの部分が、そのままUCS-2である。

コードポイントの表記法

Unicodeのうち、16ビットで表現できるコードポイント、およびUCS-2ではU+XXXXと表記する。Xは16進一桁。Unicodeにおいて21ビットに拡張された部分にあるコードポイントついては、適宜5, 6桁で表記する。また、UCS-4では8桁、U+XXXXXXXXと表記する。

UTF-8, UTF-16, UTF-32について

UCS, Unicodeともに、UTF-8, UTF-16というエンコーディングを定めている。つまり、UCSのいうUTF-8と、UnicodeのいうUTF-8は規格としては別物である(UTF-16についても然り)。
ただしどちらの規格のUTF-8/16も、変換の計算方法は同じで、U+0000〜U+FFFFの範囲では同じ配置になっているため、この範囲に限れば最終的なビット列にしても違いはない。(U+10000より後がどうなのかは知らない)。
Unicodeには更に、UTF-32というコードポイントをそのままコンピュータで扱うバイト列とするエンコーディングが定義されている。UCSには存在しないが、UCS-4は、そのままエンコーディングでもあるので、実質UTF-32とは同等である。
UCS-2もまたそのままエンコーディングでもあるが、こちらはサロゲートペアについての規定がないので、UTF-16とは違ってU+10000以降の文字は扱えない。
個々のエンコーディングの具体的な計算方法は省略。

要約すると、

ここには書いていないこと

  • UTF-8/16が具体的にどのようにして符号をバイト列に変換しているのか
  • UnicodeUTF-16/32にはバイトオーダーの話
  • 符号点と群・面・区・点、BMP
  • いくつかのコードポイントからなる合成文字について

分からないこと

vlcをCUIから使う

みなさんごきげんよう。今日も元気にラブライブ!の1stシングル「僕らのLIVE 君とのLIFE」を聞きましょう。
…あぁ、いつもいつもCD挿すのめんどくさいですね。ここはちょいとvorbisあたりに変換してハードディスクに保存してしまいましょう。誰ですかiPodとかで聞いてるのは?そんなものは知らない。見えない。分からない。
さて、手元にvlcがあります。こいつを使って収録されている曲及び各員からのコメントを変換して保存するには、トラックごとにダイアログから設定して、エンコードしてやらないといけません。おいぃ13トラックもあるぞ!手でやってられへん!!!
これはめんどくさい、一気に変換する方法はないものか…そうだ、vlcってCUIから使えねーの?と思ってvlc --helpとか打ってみたらやたらと長い説明が出てきて、それだけでは飽き足らず「網羅的なヘルプを表示するためには、'-H'オプションを指定してください。」とか言わはる。これはやばい。相当にやばい。しかし私はラブライブ!1stシングルを快適に聞くために頑張ってvlcでバッチエンコードするためのマンドを探しまくりました。ありました。やったー
というわけで、私の備忘録、兼、今日もどこかでvlcのプログラムオプションに困っている人達のために残しておきます。

サンプル

cvlc --sout-vorbis-quality=4 \
  --sout "#transcode{acodec=vorb,channels=2,samplerate=44100}:std{access=file,mux=ogg}" \
  cdda:///dev/cdrom :cdda-track=2 :sout-standard-dst=友情ノーチェンジ.ogg \
  cdda:///dev/cdrom :cdda-track=5 :sout-standard-dst=はじめまして-高坂穂乃果-.ogg

これは以下と同じです(理由は後述):

cvlc --sout-vorbis-quality=4 \
  --sout-transcode-acodec=vorb --sout-transcode-channels=2 \
  --sout-transcode-samplerate=44100 --sout-standard-access=file --sout-standard-mux=ogg \
  cdda:///dev/cdrom :cdda-track=2 :sout-standard-dst=友情ノーチェンジ.ogg \
  cdda:///dev/cdrom :cdda-track=5 :sout-standard-dst=はじめまして-高坂穂乃果-.ogg

Overview

cvlc [オプション] [[MRL] [オプション…]]…

vlcは、多くのオプションに従ってMRLごとにデータを再生(スピーカーやモニターに出力)、ストリーム出力(webに出力)、ローカルに保存(ファイルに出力)、その他何かします。
cvlcとは、GUI剥ぎ取ったvlcです。なので、vlcに同じコマンドを渡すこともできますし、ちゃんと動きます。ただしバッチ中にウィンドウ出てきてもうざいだけですが。

MRL

MRLは、入力データの場所です。ローカルファイル以外にも、web上のファイルやストリームとかでもいいです。
MRLはURLに何か色々付け足したものですが、その「何か」の部分は知りませんので知りません。URLは以下のような書式です(vlc --helpから抜粋)。

URL syntax:
  [file://]filename              Plain media file
  http://ip:port/file            HTTP URL
  ftp://ip:port/file             FTP URL
  mms://ip:port/file             MMS URL
  screen://                      Screen capture
  [dvd://][device][@raw_device]  DVD device
  [vcd://][device]               VCD device
  [cdda://][device]              Audio CD device
  udp://[[<source address>]@[<bind address>][:<bind port>]]
                                 UDP stream sent by a streaming server
  vlc://pause:<seconds>          Special item to pause the playlist for a certain time
  vlc://quit                     Special item to quit VLC

例えば、 /dev/cdrom に挿さっているオーディオCDなら、 cdda:///dev/cdrom です。
screen:// は多分、ディスプレイ出力を入力にするためのURLだと思います。ゲームのプレイ動画とか作れるかもしれませんね。
vlc://quit を見つけるとvlcは終了します。つまり、これを付けないとバッチ処理後もvlcは起動したままになります。

オプション

オプションは、グローバルなものと、MRLごとに指定するための記法の二つがあります。

--optionと書くと、全てのMRLに対するオプションになり、:optionと書くと、直前のMRLに対するオプションとなります。:optionは--optionより優先されます(この説明が完全に正しいわけじゃないっぽいです)。

また、--sout-*系のオプションは、

--sout "#module1{option1=value,option2=value…}:module2{option1=value,option2=value…}…"

という風に書くことができ、これは

--sout-module1-option1=value --sout-module1-option2=value … --sout-module2-option1=value

と同じです。
#module1{options}:module2{options}… の形式が使えるmoduleは、 transcode, standard, duplicate, rtp と、他あったような気がするけど忘れました。

個々のオプション項目

サンプルをもう一度記載します。

cvlc --sout-vorbis-quality=4 \
  --sout "#transcode{acodec=vorb,channels=2,samplerate=44100}:std{access=file,mux=ogg}" \
  cdda:///dev/cdrom :cdda-track=2 :sout-standard-dst=友情ノーチェンジ.ogg \
  cdda:///dev/cdrom :cdda-track=5 :sout-standard-dst=はじめまして-高坂穂乃果-.ogg
  • --sout-vorbis-*: Vorbisコーデックのオプション。デフォルトではVBRエンコードになっている
  • --sout-transcode-*: 入力を変換する系のオプション
    • --sout-transcode-acodec=(vorb|mpga|a52|ac3): 音声コーデックの指定
      • vorb: Vorbis
      • mpga: MPEG audio layer 2
      • a52, ac3: AC3 sound
    • --sout-transcode-ab=kbps: 音声ビットレート(kbps)(コーデックにVorbis使う場合は無視される)
    • --sout-transcode-channels=number: チャンネル数(ステレオなら2)
    • --sout-transcode-samplerate=Hz: サンプリングレート(Hz, オーディオCDなら多分44.1kHzだから44100)
  • --sout-standard-*: 出力先に関するオプション
    • --sout-standard-access=(file|udp|rtp|http): アクセス先の指定
      • file: 普通のファイル
      • udp, rtp, http: それらのプロトコルで垂れ流す(調べてないから知らない)
    • --sout-standard-mux=(avi|ogg|ps|ts): コンテナの指定
      • avi: AVI
      • ogg: OGG
      • ps: MPEG2-PS
      • ts: MPEG2-TS
    • --sout-standard-dst=url: 出力先の場所。--sout-standard-accessがfileの場合は普通にファイルのパスを指定するか、もしくはfile://の形式で指定。その他のプロトコルの場合は何かURL(調べてないから知らない)

standardには、stdという別名があるので、#module1{}:module2{}という書き方をする場合はそのstdという別名が使えます。

--sout-transcode-*には、もちろん映像関連のオプションもあります。 --sout-transcoode-vcodec=video_codec とか。

この他のmoduleも、全然使ってないけど憶測で適当に紹介します。

  • --sout-duplicate-*: 出力を分岐する
    • --sout-duplicate-dst=#module1{options…}:module2{options…} : オプションの内容に従って出力する。dstを何個も書いてやることで、出力先が増える
  • --sout-rtp-*: 指定するURLにRTPで出力

これらのオプションについて、詳細はvlc -Hや、

あたりを見てください。ちなみに上のURLのリストは多分内容が偏ってると思うので、もっと色々なことをしたい人は、勝手にwikiの中を漁ってください。
そんなわけでvlcコマンドラインから使う方法を紹介してきましたが、ぶっちゃけMRLとオプションをずらずら並べなくても、シェルのfor文使ってもいいですね。
あとなんか、--optionと:optionの関係はそんな単純なものじゃないっぽくて、まぁうまいことやってください。