altebute.hatenablog.com

犬も歩けば規格にあたる

完全栄養食COMPレビュー 意外といける

偽サイトに注意!!

COMP公式を騙る偽サイトがあります。
URLが cooomp とかになってるので要注意。

2016.04.24 追記
cooomp.com は一応公式管理のサイトだそうです。 大変申し訳ありませんでした。

味について

そこそこ飲みやすいです。 が、失敗するとゲロまずなので注意。

  • ぬるい水道水は不味いです。最低限冷やしましょう。
  • コーヒーが安定して飲めます。無糖・加糖どちらでもOK。お求めはお近くのコンビニで。
  • パイン水は甘ったるすぎてダメでした。

調理について

公式PDF にも書いてありますが、最初に少し水(または混ぜる飲料)を入れないと底に溜まった粉が混ざってくれません。私の調理法は以下のとおり。

  1. 専用シェーカーに飲料を少し入れる
  2. 粉を適量入れる。
  3. シェーカー一杯より少し少なめに飲料を入れる。
  4. 軽く振る。
  5. フタを開けて飲料を追加する。
  6. よく降って出来上がり。

飲料をちゃんと入れないと強烈に濃いマックシェイクみたいになります。 なので一度振って飲料を入れ直します。こうしないと飲料が足りない感じの出来上がりになってしまいます。

メリット

  • 栄養のバランスが取れます。当たり前ですが。
  • 調理が強烈に楽です。俺は面倒が嫌いなんだ。
  • 意外とお腹にたまり満腹感があります。

デメリット

歯ごたえが無い

基本的に完全栄養食を標榜する食品は粉末を溶いて摂取する事になるので避けられない宿命と思われますが、歯ごたえがありません。 人間噛むことを一切しないと多分とても健康に悪いので、COMPだけでなくその他の食事も摂りましょう。 最近COMPばかり食べてたのでローソンでやみつき鶏ごまラー油買ってきたらめっちゃ美味しかったです。

粉がめっちゃ舞い散る

粉が非常に細かいので、かなり舞い散ります。 お前はベビーパウダーか!という感じ。 実際には小麦粉くらいかな……? 溶けやすくするため致し方無し。 袋から粉を取り出す時と、シェーカーに粉を入れる時はそっと扱いましょう。

その他気になった事

COMP9袋、81食ででっかいダンボール箱一箱分です。一ヶ月分の食事だから当たり前ですが、重いです。 最初は2袋からはじめましょう。

改善してほしい点

オリジナルシェーカーは分量調節に便利ですが、割とフタが緩いので下手に振ると飛び散ります。 とても持ち運べるものでは無いです。シェーカーとして使えて持ち運びにも適した容器が欲しいです。

疑問点

プロモーションムービーに出てくる容器はどこで入手出来るのだろう。 持ち歩きにすごい便利そうだから欲しいのだけど…

機工城アレキサンダー:律動編 ドロップテーブル他

必要個数

種別 対価となるアイテム 必要個数
頭防具 ミダースレンズ 2
胴防具 ミダースシャフト 4
手防具 ミダースクラン 2
帯防具 ミダースチェーン 1
脚防具 ミダーススプリング 4
足防具 ミダースペダル 2
アクセサリ ミダースボルト 1

各層ドロップテーブル

1 * * *
2 * * *
3 * * *
4 * * *
  • 各層のドロップは3種類と過程( 起動編準拠 )
  • 起動編とドロップテーブルは同じっぽい
  • 4層では各プレイヤー確定で ミダースの歯車 がドロップ。週制限あり。

以下未整理メモ

各層で取得するアイテムはおそらく下記の感じ。 伝承装備は考慮していない。順不同。

  1. チェーン, ボルト, ペダル, ペダル, ボルト
  2. ボルト, ボルト, レンズ, レンズ
  3. スプリング, スプリング, スプリング, スプリング, クランク
  4. シャフト, シャフト, シャフト, シャフト, クランク

以下注釈

  • クエスト報酬でボルトは今回は無し
  • 残りのアクセ枠( 指 )は伝承で埋める。

同人活動の感想を送る上で最も妨げになるものは「面倒くささ」だと思う

TLでチラチラ話題になっていたので前々から思っていた事をアウトプット。

感想が貰えないのは、作品がつまらなかったりする場合よりも、 感想を送る行為そのものの面倒さに起因する事が多いように思う。 *1

連々と列挙すると、

  • 作者のウェブサイトを探すのが面倒くさい
  • 感想の投稿フォームを探すのが面倒くさい
  • 感想がメールだったりするとなんかやだ
  • Twitterで感想を送るのは双方向だからなんかやだ
  • 投稿フォームがあってもメールアドレス必須だと面倒くさい
  • 投稿フォームがでかいと、感想をたくさん書かなきゃいけない気がして億劫だ

etc, etc.

その点、最も感想を貰う事に向いたプラットフォームは新都社に代表されるウェブ漫画だと思う。 ウェブ漫画の特徴は、

  • 縦長のインタフェースで漫画が読める
  • 読み終わると末尾に感想を書けるテキストボックスがある
  • テキストボックスは一行である
  • メールアドレス記入欄も無い
  • ハンドルネームも不要
  • シャッと書いてEnterを押して終わり

等。素晴らしく「敷居が低い」と言える。 勿論、匿名故罵詈雑言が書き込まれる危険性等もあるのだが。

その他にも、感想が書きやすいプラットフォームにはニコニコ動画等が挙げられるが、 ニコニコ動画は作品数が多すぎて埋もれてしまう。 WEB漫画だと一定のクオリティーの作品を制作する敷居が上がるので、 ニコニコ動画と比べると埋もれづらいように思う。

*1:勿論作品がつまらないなら頑張って面白いと思うものを追求してくれとしか言えないが。

USB Type-Cの最も素晴らしい点はその剛性である

先日、Nexus 5Xを購入した。 巷ではNexus 5Xはバッテリーに問題があったり、 充電中にタッチパネルの反応が悪くなる等の問題点が指摘されているが、 私の環境では概ね良好である。

閑話休題

Nexus 5Xはデータ通信用のポートがUSB Type-Cポートになっているが、 このケーブルと端子が素晴らしい。

USB Type-Cの主なメリットは、

  • 端子に表裏が無い
  • ホスト・デバイスの端子の区別が無い
  • etc etc...

等のメリットが挙げられるが、 私的にはそれ以上に 端子の抗折力の向上 をメリットに挙げたい。

従来、同様の用途に用いられてきたUSB Micro-B端子は、 オス側の端子に垂直方向の負荷をかけると、 簡単に曲がってしまい、ツメの部分がうまく引っ掛からなくなり、 充電や接続に支障が出るようになってしまう。

また、これらは特定の会社が製造するケーブルに限った話では無く、 各社のケーブル共通の問題であるため、 規格上の問題であると言ってよいだろう。

一方で、USB Type-Cの場合はこの点が大幅に改善されている。 抜き差しの回数の強度だけでなく、 端子そのものの抗折力が向上している点は高く評価出来るだろう。

高階関数内で、引数の引数の型を取得する

いなむ先生とバンビちゃん先生にご助力頂いてやっと書けたコードです。多謝!

2016.01.03 追記 VC++では関数ポインタの型推論について、Variadic Templateのマッチングの優先順位がおかしいため正常に動作しません。

まず以下のコードについて考える。

template< typename Arg, typename Func >
void f( const Func& func )
{
    Arg arg;
    func( arg );
}

arg が未初期化になる場合についてはとりあえず考えない。 上記のコードでは、 Arg の型を明示的に指定しなくてはならない。 なんとかして、 Func から Arg の型を導出したい。

そこで、 std::function を引数とする関数に書き換える。

#include <functional>

template< typename R, typename A >
void f( const std::function< R(A) >& )
{
    A arg;
}

int main()
{
    std::function< void(int) > a;
    f( a );
}

上記のコードは通る。確かに通る。 が、lambdaや、ユーザ定義の関数オブジェクトを投げると、 std::function の型を明示的にしてやらないと推論に失敗して死ぬ。 型の指定を省略したいのに、これでは本末転倒である。

struct s
{
    void operator()( int ){}
};

int main()
{
    auto l = [](int){};
    auto o = s{};
    f< void, int >( l ); // ok
    f< void, int >( o ); // ok
    f( l ); // ng
    f( o ); // ng
}

しかも、 std::function は小さくないオーバーヘッドが生じる。 C++であるからには、可能な限りゼロオーバーヘッドの原則を貫きたい。


まず、関数ポインタについて。 引数と戻り値の型を取得する。

#include <functional>
#include <type_traits>
#include <iostream>
#include <boost/type_index.hpp>

namespace impl
{
    template< typename R, typename A > auto result_type_helper(   R( * )( A ) ) -> R;
    template< typename R, typename A > auto argument_type_helper( R( * )( A ) ) -> A;
}

template< typename F > using result_type   = decltype( impl::result_type_helper(   std::declval< F >() ) );
template< typename F > using argument_type = decltype( impl::argument_type_helper( std::declval< F >() ) );

void f( int ){}

int main()
{
    using namespace std;
    using boost::typeindex::type_id_with_cvr;
    using ft = decltype( f );
    cout << type_id_with_cvr< result_type<   ft > >().pretty_name() << endl;
    cout << type_id_with_cvr< argument_type< ft > >().pretty_name() << endl;
}

同様に関数オブジェクト。

...

namespace impl
{
    template< typename R, typename F, typename A > auto result_type_helper(   R( F::* )( A ) ) -> R;
    template< typename R, typename F, typename A > auto argument_type_helper( R( F::* )( A ) ) -> A;
    template< typename R, typename F, typename A > auto result_type_helper(   R( F::* )( A )const ) -> R;
    template< typename R, typename F, typename A > auto argument_type_helper( R( F::* )( A )const ) -> A;
}

template< typename F > using result_type   = decltype( impl::result_type_helper(   &F::operator() ) );
template< typename F > using argument_type = decltype( impl::argument_type_helper( &F::operator() ) );

struct s
{
    void operator()(char){}
};

int main()
{
    using namespace std;
    using boost::typeindex::type_id_with_cvr;
    auto l = [](double){};
    using lt = decltype( l );
    cout << type_id_with_cvr< result_type<   lt > >().pretty_name() << endl;
    cout << type_id_with_cvr< argument_type< lt > >().pretty_name() << endl;
    cout << type_id_with_cvr< result_type<   s  > >().pretty_name() << endl;
    cout << type_id_with_cvr< argument_type< s  > >().pretty_name() << endl;
}

メンバ関数ポインタを扱うため、人によっては見慣れない演算子 ::* が使われている。

ただし、関数オブジェクト内で関数がオーバーロードされている場合はうまく動かない。 そもそも、オーバーロードされている場合は明示的に指定しないと型が取得出来ないのは当然なので、 以下のように明示的に取得して使用する。

...

namespace impl
{
    template< typename R, typename F, typename A > auto result_type_helper(   R( F::* )( A ) ) -> R;
    template< typename R, typename F, typename A > auto argument_type_helper( R( F::* )( A ) ) -> A;
}

template< typename F > using result_type   = decltype( impl::result_type_helper(   std::declval< F >() ) );
template< typename F > using argument_type = decltype( impl::argument_type_helper( std::declval< F >() ) );

struct s
{
    void operator()(char){}
    void operator()(float){}
};

int main()
{
    using namespace std;
    using boost::typeindex::type_id_with_cvr;
    void( s::* c )( char  ) = &s::operator();
    void( s::* f )( float ) = &s::operator();
    using ct = decltype( c );
    using ft = decltype( f );
    cout << type_id_with_cvr< result_type<   ct > >().pretty_name() << endl;
    cout << type_id_with_cvr< argument_type< ct > >().pretty_name() << endl;
    cout << type_id_with_cvr< result_type<   ft > >().pretty_name() << endl;
    cout << type_id_with_cvr< argument_type< ft > >().pretty_name() << endl;
}

最後に、これらについて type_traits を用いて分岐を行う。 さらに、引数の型が void の場合と、2つ以上の引数に対応する。

#include <functional>
#include <type_traits>
#include <iostream>
#include <tuple>
#include <boost/type_index.hpp>

namespace impl
{
    template< typename P > struct function_pointer
    {
        template< typename R                               > static auto argument( R( * )( void       ) ) -> void;
        template< typename R                               > static auto result(   R( * )( void       ) ) -> void;
        template< typename R, typename A                   > static auto argument( R( * )( A          ) ) -> A;
        template< typename R, typename A                   > static auto result(   R( * )( A          ) ) -> R;
        template< typename R, typename A, typename... Args > static auto argument( R( * )( A, Args... ) ) -> std::tuple< A, Args... >;
        template< typename R, typename A, typename... Args > static auto result(   R( * )( A, Args... ) ) -> R;
        using argument_type = decltype( argument( std::declval< P >() ) );
        using result_type   = decltype( result(   std::declval< P >() ) );
    };
    
    template< typename P > struct member_function_pointer
    {
        template< typename R, typename C                               > static auto argument( R( C::* )( void       )      ) -> void;
        template< typename R, typename C                               > static auto result(   R( C::* )( void       )      ) -> R;
        template< typename R, typename C                               > static auto argument( R( C::* )( void       )const ) -> void;
        template< typename R, typename C                               > static auto result(   R( C::* )( void       )const ) -> R;
        template< typename R, typename C, typename A                   > static auto argument( R( C::* )( A          )      ) -> A;
        template< typename R, typename C, typename A                   > static auto result(   R( C::* )( A          )      ) -> R;
        template< typename R, typename C, typename A                   > static auto argument( R( C::* )( A          )const ) -> A;
        template< typename R, typename C, typename A                   > static auto result(   R( C::* )( A          )const ) -> R;
        template< typename R, typename C, typename A, typename... Args > static auto argument( R( C::* )( A, Args... )      ) -> std::tuple< A, Args... >;
        template< typename R, typename C, typename A, typename... Args > static auto result(   R( C::* )( A, Args... )      ) -> R;
        template< typename R, typename C, typename A, typename... Args > static auto argument( R( C::* )( A, Args... )const ) -> std::tuple< A, Args... >;
        template< typename R, typename C, typename A, typename... Args > static auto result(   R( C::* )( A, Args... )const ) -> R;
        using argument_type = decltype( argument( std::declval< P >() ) );
        using result_type   = decltype( result(   std::declval< P >() ) );
    };
    
    template< typename C > struct function_object
    {
        using argument_type = typename member_function_pointer< decltype( &C::operator() ) >::argument_type;
        using result_type   = typename member_function_pointer< decltype( &C::operator() ) >::result_type;
    };
    
    template< typename F > struct function_traits
    : public std::conditional_t
    <
        std::is_member_function_pointer< F >::value,
        member_function_pointer< F >,
        std::conditional_t
        <
            std::is_pointer< F >::value,
            function_pointer< F >,
            function_object< F >
        >
    >
    {};
}

template< typename F > using argument_type = typename impl::function_traits< std::decay_t< F > >::argument_type;
template< typename F > using result_type   = typename impl::function_traits< std::decay_t< F > >::result_type;

struct s
{
    void operator()(int){}
};

struct o
{
    void operator()(char){}
    void operator()(void){}
};

void f( float, double ){}

int main()
{
    using namespace std;
    using boost::typeindex::type_id_with_cvr;
    
    auto l = [](long){};
    void( o::* c )( char ) = &o::operator();
    void( o::* v )( void ) = &o::operator();
    
    using ft = decltype( f );
    using lt = decltype( l );
    using ct = decltype( c );
    using vt = decltype( v );
    
    cout << type_id_with_cvr< result_type<   s  > >().pretty_name() << endl;
    cout << type_id_with_cvr< argument_type< s  > >().pretty_name() << endl;
    cout << type_id_with_cvr< result_type<   lt > >().pretty_name() << endl;
    cout << type_id_with_cvr< argument_type< lt > >().pretty_name() << endl;
    cout << type_id_with_cvr< result_type<   ct > >().pretty_name() << endl;
    cout << type_id_with_cvr< argument_type< ct > >().pretty_name() << endl;
    cout << type_id_with_cvr< result_type<   vt > >().pretty_name() << endl;
    cout << type_id_with_cvr< argument_type< vt > >().pretty_name() << endl;
    cout << type_id_with_cvr< result_type<   ft > >().pretty_name() << endl;
    cout << type_id_with_cvr< argument_type< ft > >().pretty_name() << endl;
}

上記の関数は、引数が2つ以上の場合は std::tuple を戻す。 gcc 5.2.0 では完動するが、clang 3.8.0では std::tuple の型名を取得すると何故か以下の実行時エラーで例外が送出される。

terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<std::runtime_error> >'
  what():  Type name demangling failed

Anker PowerLine USB-C & USB 3.0 Cableは規格に準拠していて安全らしい

Googleのエンジニアである、Benson Leung氏が、Amazonで片っ端からUSB-Cケーブルをレビューし、規格違反のケーブルを弾劾しているのは周知の事実である。

今回は、Google Nexus 5Xを購入したので、定番であるAnkerのケーブルを買う事にした。 Ankerのケーブルで、2015年12月12日現在、Benson氏の直接のレビューがあるのは以下の1製品のみ。

Anker's USB-C to USB 3.0 Cable uses a spec compliant 56kΩ identification resistor, great 3rd party SuperSpeed cable

だそうです。おすすめ。

std::as_const と sprout::as_cont の違い

std::as_constsprout::as_const は、何れも引数を const 修飾された型に変換する関数テンプレートである。尚、 std::as_constC++17にむけて提案されている関数であるため、実装されている環境は少ない。

Constant View: A proposal for a std::as_const helper function template

sprout::as_const はSprout全体において運用される、処理をコンパイル時に行うための記述が含まれるが、それについては本記事の主旨ではないため触れない*1

std::as_constsprout::as_const の最も顕著な違いは、 sprout::as_const は実引数が rvalue の時、戻り値の型が rvalue reference になるのに対し、 std::as_const は実引数が rvalue であっても戻り値の型は lvalue reference となる。

rvalue 対応版

#include <type_traits>
#include <iostream>
#include <utility>
#include <boost/type_index.hpp>

using namespace std;
using boost::typeindex::type_id_with_cvr; 

template< typename Arg >
std::conditional_t
<
    std::is_lvalue_reference< Arg >::value,
    std::add_lvalue_reference_t< std::add_const_t< std::remove_reference_t< Arg > > >,
    std::add_rvalue_reference_t< std::add_const_t< std::remove_reference_t< Arg > > >
>
inline as_const( Arg&& arg )noexcept
{
    return std::forward< Arg >( arg );
}

template< typename Arg > void f( Arg&& arg )
{
    cout << "arg is " << type_id_with_cvr< decltype( arg ) >() << endl;
}

int main()
{
    int a;
    f( a );
    f( move( a ) );
    f( as_const( a ) );
    f( as_const( move( a ) ) );
}

出力

Start
arg is int&
arg is int&&
arg is int const&
arg is int const&&
0
Finish

当然ながら、 std::forwardstd::move を適切に使用する必要がある。

lvalue

...
template< typename Arg >
std::add_lvalue_reference_t< std::add_const_t< std::remove_reference_t< Arg > > >
inline as_const( Arg&& arg )noexcept
{
    return std::forward< Arg >( arg );
}
...

出力

Start
arg is int&
arg is int&&
arg is int const&
arg is int const&
0
Finish

何れも簡易的な実装であり、提案された文書とは実装が異なる。

初期の提案では右辺値を渡された場合の変数の寿命延長について考慮し、 右辺値を受け取った場合はコピー演算を行うバージョンについても記述されていたが、 最新の文書では無くなっているため問題ないと判断されたのであろう。

右辺値をどう扱うかの違いによって生じる影響については機会があればまた論じたい。

私はSproutの右辺値も扱えるバージョンが好きだな。

*1:というか私が理解してない