江添亮
株式会社ドワンゴ
C++標準化委員会 エキスパートメンバー
Blog: http://cpplover.blogspot.jp/ Mail: boostcpp@gmail.com Twitter: https://twitter.com/EzoeRyou GitHub: https://github.com/EzoeRyou
ISOの下位組織
国家単位で活動組織が存在する
日本の場合、ITSCJ
ISOの規程に基づき
C++標準化委員会の文書は
文書番号を付与して公開される
国際会議の案内、予定表、議事録
ドラフト文面、既知の問題集
問題点の考察
新機能の提案
新技術の紹介
注意
提案段階の文法や機能はまだ大幅に変わる可能性がある
そもそも採用されるかどうか分からない
実用できるのは10年は先の話
struct X { int a ; double b ; std::string c ; } ;
struct X { bool operator == ( const X & rhs ) const noexcept { return a == rhs.a && b == rhs.b && c == rhs.c ; } bool operator != ( const X & rhs ) const noexcept { return !( *this == rhs ) ; } } ;
struct X { bool operator < ( const X & rhs ) const noexcept { return std::tie( a, b, c ) < std::tie( rhs.a, rhs.b, rhs.c ) ; } bool operator > ( const X & rhs ) const noexcept { return rhs < *this ; } bool operator <= ( const X & rhs ) const noexcept { return !( rhs < *this ) ; } bool operator >= ( const X & rhs ) const noexcept { return !( *this < rhs ) ; } } ;
そもそも
各データメンバーが比較できるのであれば
機械的に生成できるではないか
比較演算子を自動生成
明示的に宣言することでデフォルト生成
互換性のために明示的に記述
既存のコードの意味を変えてはならない
struct X { int a, b, c ; bool operator == ( const X & ) = default ; bool operator != ( const X & ) = default ; bool operator < ( const X & ) = default ; bool operator > ( const X & ) = default ; bool operator <= ( const X & ) = default ; bool operator >= ( const X & ) = default ; };
struct X { int a, b, c ; default: ==, !=, <, >, <=, >= ; } ;
暗黙に生成することを提案
"x ? x : y"を"x?:y"に
xがtrueならばxを、falseならばyを返す
x ? x : y ;
xが重複している
間違えやすい
式が二度評価されるため非効率的
// 重い計算処理 int calculate_value() ; int fallback_value = 100 ; calculate_value() ? calculate_value() ? fallback_value ;
面倒くさい
機械的に変換できる
コンパイラーにやらせればよい
auto && temp = calculate_value() ; temp ? temp : fallback_value ;
x ?: y ;
以下と同等
auto && temp = x ; temp ? temp : y ;
if ( std::shared_ptr<T> ptr = obj.lock() ) { do_something( *ptr ) ; }
もっと短く書きたい
if ( T & x : obj.lock() ) { f( x ) ; }
if ( auto && __p = obj.lock() ) { T & x = * __p ; f( x ) ; }
if ( x : e ) s ;
展開すると
if ( auto && __p = e ) { auto && x = * __p ; s ; }
もしくは、インライン式?
隠匿式とも
呼ばれるたびに初期化子が評価される変数
int runtime_data( { static int count ; return ++count ; } inline int data = runtime_data() ; int main() { data ; // 1 data ; // 2 data ; // 3 }
ストレージが確保されないことを保証
ODR回避
void draw_rect( int left, int top, int width, int height ) int main() { // どれがどれだっけ? draw_rect( 30, 30, 200, 300 ) ; }
int main() { // わかりやすい draw_rect( left : 30, top : 30, width : 200, height : 300 ) ; // 順番も変えられる draw_rect( top : 0, left : 0, width : 640, height : 480 ) ; }
operator . ()をユーザー定義したい
class string_ref { std::string value ; public : std::string & operator . () { return vlaue ; } } ; int main() { string_ref ref ; // std::stringのlength ref.length() ; // ref.operator .() = "hello" ref = "hello" ; }
スマートリファレンスを定義できる
template < typename T > class Ref { T * p ; public : Ref( ) : p( new T() ) { } ~Ref() { delete p ; } T & operator . () { return *p ; } } ;
こういうクラスがある場合
class string_ref { std::string value ; public : std::string && operator .() { return value ; } std::size_t size() ; } ;
クラスにメンバーがある場合は優先される
int main() { string_ref ref ; // string_refのsize ref.size() ; // std::stringのlength ref.length() ; }
UTF-8コード単位ひとつで表現できる文字を記述できる
// OK char c = u8'c' ; // エラー char あ = u8'あ' ;
深い名前空間のネストは面倒
namespace A { namespace B { namespace C { } } }
簡潔に書けるようになる
namespace A::B::C { }
x.f( y, z )
を
f( x, y, z )
と同等にする
メンバー関数とフリー関数は呼び出しの文法が異なる
汎用的なコードの妨げになる
template < typename T > void f( T & a, T & b ) { // Tはクラスの場合 a.swap( b ) ; // Tがクラスではない場合 swap( a, b ) ; }
コードの汎用性を上げるため
メンバー関数を使わないようにしよう
Fucntions Want to be free.
関数は自由になりたがっている。
-- Scott Meyers
関数呼び出しの文法を統一してしまえばよい
x.f(y) を f( x, y ) と同等にすればよい
コード補完が強力になる
void f( std::FILE * fp ) { // コード補完可能 fp->fseek }
move, swap, addressofなど
汎用的すぎる関数が大量にある
それほど便利にはならない
fp->for_each
こう書けるようになる
struct Node { // 現状では未定義 std::vector<Node> node_list ; } ;
クラスは定義後に完全形になる
class Node ; // 宣言 Node n ; // エラー、不完全型 Node * p ; // OK class Node { } ; // 定義 Node n ; // OK
コンテナーで不完全型に対応するのは可能
規格で規定されていない
実装ごとに対応はバラバラ
GCD - Greatest Common Divisor
最大公約数
LCM - Least Common Multiple
最小公倍数
std::gcd( 10, 25 ) ; // 5 std::lcm( 123, 456 ) ; // 18696
まだ採用されていないものの
かなり確実に採用される
すでにClang上流で実装済み
必ず文字列リテラルが必要
static_assert( constant-expression , string-litera ) ;
// エラー static_assert( expr ) ; // OK static_assert( expr, "" ) ;
Clangで実装済み
for ( T elem : range ) statememt ;
template < typename Container > void f( Container & c ) { for ( Container::value_type & elem : c ) { // ... } }
正しく使うのが面倒
なぜこう書かねばならぬかは論文参照
for ( auto && elem : c ) { // ... }
auto &&と同じ意味になる
Clangに実装済み
for ( elem : range ) { // ... }
C++には不思議な文法上の制約がある
template < template < typename T > // classキーワードのみ使える class U > struct X ;
Clangで実装済み
template < template < typename T > // OK typename U > struct X ;
このスライド資料はドワンゴ勤務中に書かれた
ドワンゴは本物のC++プログラマーを募集しています