読者です 読者をやめる 読者になる 読者になる

とくにあぶなくないRiSKのブログ

危ないRiSKのブログだったかもしれない。本当はRiSKだけどググラビリティとか取得できるIDの都合でsscriskも使ったり。

【VOCALOID・Orpheus】塔【島白】

島白(よだれP)さんの新曲がでました! 民族・ロック・ドラムンベースが混ざったような曲調です。かっこいい!

前回に引き続きOrpheusを活用した曲です。原曲は塔 しまじろ

この原曲をセルフアレンジしたのが今回の新曲です。

【VOCALOID・Orpheus】塔【島白】 - ニコニコ動画:GINZA

constexprとrvalue参照問題

constexprとメンバ関数の呼び分け問題

小ネタ - constexpr の文脈でconstメンバ関数と非constメンバ関数を呼び分ける - ボレロ村上 - ENiyGmaA Code

このエントリで指摘されているように、constexprとメンバ関数の呼び分け問題があります。一時オブジェクトはconst修飾されていないために、constexprであるconst修飾メンバ関数が呼ばれないのが原因です。

template<typename T>
struct X {
    T t;
    T& get() { /* 非const版 */
        return t;
    }
    constexpr T const& get() const { /* const版 */
        return t;
    }
};

template<typename T>
constexpr auto get(T&& t) -> decltype(t.get()) { /* 引数を T&& で受ける */
    return t.get();
}

int main() {
    constexpr int i = get( X<int>{1} );
}

[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ エラーになっていますね。

メンバ関数get内のreturn t.get();に注目すると、tX&&型である(const修飾されていない)ために、constexpr T const& get() constではなくT& get()が呼ばれてしまい、結果constexprではなくなってしまいます。

Xconst_castを使ってconst修飾することで問題を解決しているようです。

constexprとmove阻害問題

moveを阻害しないconstexprの文脈でのconstメンバ関数と非constメンバ関数の呼び分け - ここは匣

さらにこのエントリで指摘されているように、「constexprとメンバ関数の呼び分け問題」に対処しようとすると、constexprとmove阻害問題が起きます。

const修飾をして、無理やりconstexpr版のメンバ関数を呼ぶので、メンバ関数の返却値の型までconst修飾されてしまい、正しくmoveされなくなってしまいます。

[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ

そこで、X<T>const_castを使ってconst修飾した後、さらにTconst_castを使ってconstはがしして問題を解決しているようです。

constexprとrvalue参照問題

「constexprとメンバ関数の呼び分け問題」と「constexprとmove阻害問題」は、constexprとrvalue参照問題と言い換えることができます。rvalue参照は一時オブジェクトも含みます。

そもそも「constexpr の文脈」とは何でしょうか? それはT const &T&&のケースです。ですから、それを素直に表せばいいのではないでしょうか。今のC++(C++11,C++14)には、その機能があります。

それはメンバ関数の参照修飾(ref-qualifier)です *1

// clang 3.2, 3.3に対応する場合はsproutを利用する

#include<utility>
// #include<sprout/utility/move.hpp>
// #include<sprout/utility/forward.hpp>

template<class T>
struct X
{
    T t;
    T& get() & // ref-qualifierを使う場合、すべてのオーバーロードにref-qualifierが必要
    {
        return t;
    }
    constexpr T const& get() const & // ココ!
    {
        return t;
    }
    constexpr T get() && // ココ!
    {
        return std::move(t);
        // return sprout::move(t);
    }
};

template<class T>
constexpr auto get(T&& t) -> decltype(std::forward<T>(t).get())
{
    return std::forward<T>(t).get(); // シンプル!
    // return sprout::forward<T>(t).get();
}


#include <iostream>

template<class T>
struct Y
{
    Y(const T&) { std::cout << "copy" << std::endl; }
    Y(T&&) { std::cout << "move" << std::endl; }
};

int main()
{
    static_assert(std::is_same<decltype(get(X<int>{0})), int>::value, "");
    Y<int> y((get(X<int>{1}))); // move対応! ヤター!
    constexpr int a = get(X<int>{2}); // constexpr対応! ヤター!
    std::cout << a << '\n';
}

[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ

このように、クラス側でT const &T&&オーバーロードconstexpr指定すると、非メンバ関数getでは、ごく普通にstd::forward<T>(t).get()するだけで、constexpr対応かつmove対応できます。

ただし、このコードが動作するのは現状Clangだけです。GCCでは現状最新の4.10 HEADを含むすべてで動作しません。GCCでは

prog.cc:17:17: note: candidate: constexpr T X<T>::get() const && [with T = int]

のようにエラーが出てしまいます。これはconstexpr指定でメンバ関数が勝手にconst修飾されるC++11の仕様のためで、GCCはまだC++14のconstexprに対応していないようです。

このエントリはC++14以降に対応したコンパイラのみで有効です。なおメンバ関数の参照修飾自体はC++11からあります。

*1:当然、それに加えcv修飾(cv-qualifier)も含みます

Overloaded Lambdas

自分用に経緯とリンクをまとめ

Overloaded Lambdas 元ネタ

ブログエントリ C++ Truths: Fun with Lambdas: C++14 Style (part 2)

スライド (slideshare) Fun with Lambdas: C++14 Style (part 2)

発展

私が Clang でしか動作せず、GCC ではコンパイルエラーになることに気づく。

[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ

@fimbul11 さんが、コンパイルエラーになる GCC の挙動が正しいことを調べ、正しく Clang/GCC で動作する改善コードを書く。

make_overloadを書いた - ここは匣

[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ

Boost.OverloadedFunction

Boost に似たようなことができる boost::overloaded_function がある。overloaded_function は、ラムダ以外にも対応している。

参考

boost::overloaded_functionを使ったオーバーロードって素晴らしいですよね! - とくにあぶなくないRiSKのブログ

Boost.Functional/OverloadedFunction を試してみた - C++でゲームプログラミング

make_overloaded_function 使ってみた。 - C++でゲームプログラミング

Chapter 1. Boost.Functional/OverloadedFunction 1.0.0 - 1.55.0

ラムダ以外にも対応

@Fuyutsubaki さんが、関数へのポインタに対応させる。

[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ

(追記)先人がいた

lambda の make_overload の話題 - C++でゲームプログラミング

【VOCALOID・Orpheus】ローテーション【島白】

島白(よだれP)の新曲。

島白さんが、Orpheus (オルフェウス) という自動作曲システムに歌詞・その他必要な項目を入力して、出力された曲を元にアレンジを加えています。

【VOCALOID・Orpheus】ローテーション【島白】 - ニコニコ動画:GINZA

自動作曲したオリジナル

ローテーション しまじろ Orpheus (オルフェウス): 自動作曲システム - open.php

経緯

自動作曲システム・Orpheusが再開:ほわいとあいらんど瓦版 - ブロマガ

新曲アップしました:ほわいとあいらんど瓦版 - ブロマガ

最近読んだ本

日経ソフトウエア 2014年 05月号

ボレロ村上さんのconstexprの記事を読むために買いました。 特集4の「C++の最新機能を学ぶ constexprが開くコンパイル時プログラミングの世界」です。

constexprの基本は当然ながら、ボレロさんのSproutライブラリの紹介まで話が展開しています。日経ソフトウエアに掲載されることで、頭のおかしい人専用のライブラリではなくカジュアルにconstexprを使えるライブラリとして知られるようになったと思います。

6月号ももう出ています。

フリーソフトウェアと自由な社会 ―Richard M. Stallmanエッセイ集

以前にも読んだのですが (最近読んだ本 - とくにあぶなくないRiSKのブログ) 思うところがあって再読。

初めて読んだ時には、GPLの仕組みの良さにすごく感激したのですが、今回はそこまで感激はしませんでした。すでに知っていた事なので当然かもしれません。

RMSは、理想主義のようで理想だけで終わらず現実を変える行動をする点で、やっぱりハッカーですね。私も行動して手を動かさないとなーと思ったり。

GCC 4.9がリリース

GCC 4.9.0 がリリースされました!!

GCC 4.9.0 released, full of improved C++11 and C++14 features : Standard C++ GCC, the GNU Compiler Collection - GNU Project - Free Software Foundation (FSF)

GCC 4.9.0 released [2014-04-22]

GCC 4.9 Release Series - GNU Project - Free Software Foundation (FSF)

新機能 GCC 4.9 Release Series — Changes, New Features, and Fixes - GNU Project - Free Software Foundation (FSF)

ドキュメント GCC 4.9.0 manuals - GNU Project - Free Software Foundation (FSF)