江添亮
株式会社ドワンゴ
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++プログラマーを募集しています