Rokiのチラ裏

学生による学習のログ

気になる内容メモ about C++1z #4

今回も仕事帰りの電車の中、スマホからの投稿。iPhoneを用いているのだが、コードを随時一応コンパイルにかけたいのもあってCppCodeというiOSのアプリを使ってみているのだが、非常に辛い。そもそも、エラーメッセージを見る事ができないし、当然だがC++1zに対する対応はほぼ皆無に等しい。何か良い手立てはないものか。 …まあ、スマホでコードを書く事自体、邪道なのは分かってるけど。。

as_const template function

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

引数として渡されたrvalueでないオブジェクトをconstに変換するtemplate functionが追加されるとの事。rvalueなオブジェクトを渡すのはill-formedとなる。 constと非constのfunction overload時に意図的にconstを引数に取る関数を呼び出せるようにするのが目的とのこと。

#include<utility>

typedef unsigned int uint;

void A(const uint&){}
void A(uint&){}

int main()
{
    const uint a=0;
    uint b;

    A(a);
    A(std::as_const(b)); // calling A(const int&)
    std::as_const(std::move(b)); // ill-formed because the argument is rvalue reference
}

Ruminations on lambda captures

P0018r1 : Lambda Capture of *this by Valueに対しての文書。lambda式でデフォルトキャプチャー[=]が使われた場合に、クラスのメンバーはthisポインター経由ではなく、データそのものをキャプチャーする挙動に変更するとどのようになるかを考察している。 自分としては若干変えた方が本質的には良いとは思うが。

P0207R0:Ruminations on lambda captures

This paper explores what the suggested changes to the capture-default might mean. This paper specifically doesn't try to claim that any of the changes would have an effect on any particular amount of existing code, and admits that the examples in this paper are somewhat concocted and for illustrative purposes only.

とあるので反対なんだろうなあと思いつつも納得できる箇所が何点かあったので、一概にどちらが良いとは言い切れないなあ。しかしP0018r1で掲げている問題は本質的な意味を問う上では重要な項目だと思う。

Truly capturing the *this object by value allows an implicitly declared closure to be copied before invoking the closure's function.

A Proposal to Add Y Combinator to the Standard Library

A Proposal to Add Y Combinator to the Standard Library lambda式で再帰的な式を書く際にvariable initializingや代入時に定義する型をstd::functionと明確に定義するのではなく、auto推論に任せられるようにするためのライブラリの提案。
以下は従来の書き方。

#include<iostream>
#include<functional>
#include<utility>

int main()
{
    typedef std::function<int(int)> F;
    typedef unsigned int uint;
    constexpr uint how(100);
    
    F f([&f](uint a){return a>how?a:f(a+a);});
    // auto f([&](uint a){return a>how?a:f(a+a);}); // ill-formed   
    std::cout<<f(1)<<std::endl;
    std::move(f);

    F fc([&fc](uint a){return a==1?1:a*fc(a-1);});
    // auto fc([&fc](uint a){return a==1?1:a*fc(a-1);}); // ill-formed
    std::cout<<fc(5)<<std::endl;
}

しかしこういったコードには以下の問題があるとのこと。(p0200r0mから引用)

The solution has several disadvantages:
  • Verbosity: we have to write the signature of the lambda function twice: in std::function and in the lambda itself.
  • Unnecessary overhead: we resort to type erasure, which leads to the likely use of the heap and indirect function calls.
  • The solution does not work with generic lambdas.
  • The resulting std::function object has broken copy semantics: its copies refer to the original object through the lambda capture and become largely useless once the original object is destroyed.

Y Combinbatorライブラリを実装する事によって以下のような記述が可能となる。

That enables the following fast and clean code, free from the above problems
#include<iostream>
#include<functional>
#include<utility>

int main()
{
    typedef std::function<int(int)> F;
    typedef unsigned int uint;
    constexpr uint how(100);
    
    // F f([&f](uint a){return a>how?a:f(a+a);}); // same meaning 
    auto f(std::y_combinator([&f](uint a)->uint{return a>how?a:f(a+a);}));
    std::cout<<f(1)<<std::endl;
    std::move(f);

    // F fc([&fc](uint a){return a==1?1:a*fc(a-1);}); // same meaning
    auto fc(std::y_combinator([&fc](uint a){return a==1?1:a*fc(a-1);}));
    std::cout<<fc(5)<<std::endl;
}

実装的にはC++11から依存関係的にもクリアしているのでこれは早く個人的にも標準化してほしい。

Add Constexpr Modifiers to Functions in <algorithm> and <cstring> Headers

A Proposal to Add Constexpr Modifiers to Functions in <algorithm> and <cstring> Headers

The Standard Library provides a great collection of containers and algorithms, many of which currently lack constexpr support. Even a simple constexpr usage requires reimplementing a big bunch of the Standard Library.

との事で<algorithm>をconstexpr化する提案。多くのアルゴリズムは<cstring>に依存しているので、<cstring>もconstexpr化する。またstd::memmoveとstd::memcpyは標準ライブラリの中でも広く使用され、それをconstexprする事はステップアップとして必要だ、とのこと。

The Standard Library provides a great collection of containers and algorithms, many of which currently lack constexpr support. Even a simple constexpr usage requires reimplementing a big bunch of the Standard Library. Consider the simple example:
#include <array>
#include <algorithm>
 
int main() {
    // OK
    constexpr std::array<char, 6> a { 'H', 'e', 'l', 'l', 'o' };
        
    // Failures:
    // * std::find is not constexpr
    // * std::array::rbegin(), std::array::rend() are not constexpr
    // * std::array::reverse_iterator is not constexpr
    constexpr auto it = std::find(a.rbegin(), a.rend(), 'H');
}
This proposal concentrates on constexpr algorithms, deferring simple containers and iterators to a separate proposal. A proof of concept implementation for some algorithms, is available at: rhalbersma and Boost.Algorithm.

という事で確かに折角constexprで宣言初期化できても"a great collection of containers and algorithms, many of which currently lack constexpr support"なのが現状では多くて、constexprの意味がないよなあ。

この提案は、constexprアルゴリズムと、簡単なコンテナと、イテレータを別個の提案に延期すると述べている。またアルゴリズムの概念がrhalbersma and Boost.Algorithmにあると書いてあるので後でコードを見てみる事にする。

Wording for fallthrough attribute.

switch文のcaseラベルを通り抜けるのが意図的であると明示的に記述できるfallthrough属性の文面案

P0188R0: Wording for [[fallthrough]] attribute.

何も処理をしていないcase 1,2は特に触れてこないのだがcase 3のようにstatementを処理に加えるとbreakを書き忘れていないかという警告をコンパイラがしてくる。しかし、その意味が以下コード内のif文に書かれた内容と同じ意味なのであればswitch文の内容は間違っていない。
int main()
{
    auto f([]{});
    auto f1([]{});
    constexpr unsigned int n=0;
    
    switch(n){
        case 1:
        case 2:
            break; // OK,no statements between case labels
        case 3:
            f(); // WARNING:no fallthrough stamement
        case 4:
            f1();
    }

    if(n==4){
        f();
        f1();
    }else if(n==5)
        f1();
}
以下のように書ける。
switch(n){
        case 1:
        case 2:
            break;
        case 3:
            f();
            [[fallthrough]];
        case 4:
            f1();
    }
現時点(2016/6/9 Thu)最新版のGCC6.1.0ではこの機能はavailableではない。*1

Wording for nodiscard attribute

Wording for [[nodiscard]] attribute

関数の戻り値を使わないとコンパイル時警告されるnodiscard attributeと戻り値を使わなかった場合ill-formedとなるcontext-sensitive keywordとしてのnodiscardについての文面案。現在最新のGCC(6.1.0)ではnodiscard attributeの付与はavailableだがcontext-sensitive keywordとしてのnodiscardはno available。
$ cat test.cpp
[[nodiscard]] bool func(){return false;}
[[nodiscard]] struct St{};
// 4.8 ([[gnu::warn_unused_result]]) 7 (P0189R1)

unsigned int F() nodiscard{return 0;}
// No available

int main()
{
    func(); // WARNING
    []{return St();}(); // WARNING
    F(); // ill-formed
}

$ g++ -std=c++1z test.cpp
test.cpp:1:25: 警告: ‘nodiscard’ 属性指示が無視されました [-Wattributes]
 [[nodiscard]] bool func(){return false;}
                         ^
test.cpp:2:22: 警告: attribute ignored in declaration of ‘struct St’ [-Wattributes]
 [[nodiscard]] struct St{};
                      ^~
test.cpp:2:22: 備考: attribute forstruct St’ must follow the ‘struct’ keyword
test.cpp:5:18: エラー: expected initializer before ‘nodiscard’
 unsigned int F() nodiscard{return 0;}
                  ^~~~~~~~~
test.cpp: 関数 ‘int main()’ 内:
test.cpp:12:4: エラー: ‘F’ was not declared in this scope
  F();
    ^
12行目はGCC6.1.0ではサポートしていない構文となるので12行目についてのエラー文は適正ではない。

このエントリ内容とは全く関係のない余談 (全くC++に関する事ではないので適当に読み飛ばし推奨...)

エントリ内容とは直接的に関係のない全くの余談なのだが、このhatenaブログで<blockquote>で引用を表現したい時、そのblockquote内部でulタグによってリスト化しようとすると、どうもlist-style-position:outside;のような描写にデフォルトでなっている気がする。このエントリを書く時は取り敢えず自前でstyleタグを書いて、流石にliタグで指定するとどこかに干渉しそうでアレだったので、クラスを定義してliタグに全て割り振り、insideに設定した。(以下のように書いた

<style>
.lists{list-style-position:inside;}
.yodan h2,
.yodan p{color:rgb(100,100,100);}
.yodan h2 span{font-size:10px;}
hr{border:solid rgb(100,100,100) 1px;}
</style>

しかし...毎回これをやるのは面倒だなあ。何か設定とかないものなのだろうか。