C++14とlambda

6777 ワード

C++14について
Hurb Sutterの「C++の未来」と題した講演によると、C++標準委員会はC++11標準を発表した後、あまり休みを取らずに次世代の基準に投入された.(C++14およびC++17)の策定作業において、来年発売予定のC++14は、現在のC++11規格を修正し、整備することに位置づけられている.時間的余裕はないが、次世代規格のC++14には、依然として注目される新しい特性が含まれている.現在の提案から見ると、C++14における最大の新しい特性は、lambdaおよび通常の関数機能の拡張である.以下は新しい基準に加わる可能性が高い関連コンテンツがあります.
 
自動導出関数およびlambda戻り値のタイプ
現状:lambdaが返す値のタイプは、明確に指定する必要がなく、コンパイラによって自動的に導出できます.
//lambda       return   ,      void
[](){std::cout << "Hello";};
//              
[]()->void{std::cout << "Hello";};

//lambda          return   ,                  
[](int x){return x + 1;};
// return     x + 1    int,        int
//              
[](int x)->int{return x + 1;};
欠陥:コンパイラはlambdaおよび関数戻り値タイプを自動的に導く能力を備えていないことが多い.
//  lambda,      ,             ,
//                  ,      
[](int x)->int{int y = x + 1; return y;};

//           ,            
//                  ,      
int f(int x){return x + 1;}

//           ,               
//                  ,      
template
auto mul(const T& t, const U& u) -> decltype(t * u)
{
	return t * u;
}
対策:多くの場合、コンパイラはlambdaおよび関数戻り値タイプを自動的に導出する能力を有する.
注意:次のC++コードには、予想される言語の新しい特性が含まれています.コンパイラではサポートされていません.
//lambda                 ,      
[](int x){int y = x + 1; return y;};

//               auto
//               
auto f(int x){return x + 1;}

//               auto
//               
template
auto mul(const T& t, const U& u)
{
	return t * u;
}

単一状態lambdaと多状態lambda
現状:現在の標準のlambdaは単一状態(monomorphic)lambdaに属する.すなわち、lambdaパラメータのタイプは明確に指定されなければならず、コンテキストを介してコンパイラによって自動的に導くことはできない.
std::for_each( begin(v), end(v), [](decltype(*begin(v)) x){ std::cout << x; } );
//for_each          
//                                  
//                lambda       x        v     
//                lambda       
//    v   x         :decltype(*begin(v))
欠陥:現在の標準には、マルチステート(polymorphic)lambdaまたは汎用(generic)lambdaは存在しません.つまり、言語にパラメータタイプが欠けている場合、コンパイラがコンテキストに基づいて自動的に導出できるlambdaがありません.
次のような機能のC#コードを比較してみます.
lst.ForEach(x => { Console.WriteLine("{0}", x); });
//  List ForEach      List
//                       
//            lambda       x        lst     
//  C#              lambda       
//      lst   x   
対策:汎用(generic)lambda(パラメータタイプはコンパイラがコンテキストに基づいて自動的に導出できるlambda)という新しい特性を追加します.
注意:次のC++コードには、予想される言語の新しい特性が含まれています.コンパイラではサポートされていません.
//    lambda         
//     (     ,            ,    )
std::for_each( begin(v), end(v), [](x){ std::cout << x; } );
//     (    )
std::for_each( begin(v), end(v), [](&x){ std::cout << x; } );
//     (    )
std::for_each( begin(v), end(v), []<>(&x){ std::cout << x; } );
//     (      ,C++        ,       )
std::for_each( begin(v), end(v), [](auto& x){ std::cout << x; } );

テンプレートパラメータ付きlambda
現状および欠陥:現在の規格にはテンプレートパラメータ付きlambdaは存在しない.
//                lambda
template
auto mul(const T& t, const U& u) -> decltype(t * u)
{
	return t * u;
}
対策:テンプレートパラメータ付きlambdaという新しい特性を追加します.
注意:次のC++コードには、予想される言語の新しい特性が含まれています.コンパイラではサポートされていません.
//       lambda
auto mul = [](const T& t, const U& u){return t * u;}

関数体が式のlambda
現状:lambdaの関数体には、大きな括弧を用いたブロックという形式しかない.
//       lambda(                 return  ),             
auto f = [](int x){return x + 1;};

//  lambda
[](int x)->function(int)>{
	return [=](int y)->function{
		return [=](int z){
			return x + y + z;
		};
	};
};
欠陥:C#言語に比べて、最も簡単なlambdaの書き方は簡潔ではありません.
次のような機能のC#コードを比較してみます.
//C#  lambda           。
Func = x => x + 1;

//  lambda
Func>> g = x => y => z => x + y + z;
対策:最も簡単なlambdaの関数体が式形式を採用することを許可する.
注意:次のC++コードには、予想される言語の新しい特性が含まれています.コンパイラではサポートされていません.
//  lambda           
auto f = [](int x)x + 1;

//  lambda
[](int x)->function(int)>
	[=](int y)->function
		[=](int z) x + y + z;
対策:言語の一貫性を考慮すると、通常の関数および関数テンプレートがlambda構文に変更されると、関数体も式形式を使用することが許可されます.
注意:次のC++コードには、予想される言語の新しい特性が含まれています.コンパイラではサポートされていません.
//     lambda  
//       
template
auto mul(const T& t, const U& u) -> decltype(t * u)
{
	return t * u;
}
//       
template
[] mul(const T& t, const U& u) t * u;

Lambdaのキャプチャ式
現状:lambdaの関数内では,参照キャプチャ,値キャプチャなどのキャプチャ方式によりlambdaの周辺で定義された局所変数およびクラスメンバー変数をキャプチャして使用できる.
//    
int n = 1;
[&](){
    n++; // n==2
}();
// n==2

//   
int n = 1;
[=]()mutable{
    n++; // n==2
}();
// n==1
欠陥:移動キャプチャでは実現できないなど、キャプチャ方式がまだ不足している.
//      ,        
std::vector p;
auto f = [](std::vector&& p2){}
f(std::move(p));
対策:キャプチャ式を導入することにより、汎用的なキャプチャ方式を実現する.
注意:次のC++コードには、予想される言語の新しい特性が含まれています.コンパイラではサポートされていません.
//             
std::vector p;
auto f = [p2 = std::move(p)](){}
f();

Lambdaパラメータの相関拡張
現状と欠陥:lambdaの関数署名には通常の関数と比較してデフォルトパラメータがなく,パラメータ名も省略できない.
//              lambda
int f(int x = 0){return x + 1;}
void g(int /* unused */){std::cout << "g";}
対策:lambdaの関数署名にデフォルトパラメータを付けることを許可し、パラメータ名を省略することを許可する.
注意:次のC++コードには、予想される言語の新しい特性が含まれています.コンパイラではサポートされていません.
//             
auto f = [](int x = 0){return x + 1;};
auto g = [](int /* unused */){std::cout << "g";};

具名lambda
現状と欠陥:lambdaには名前がなく、リロードや再帰ができない.
//lambda    ,     
auto f1 = [](int x){std::cout << "f int";};
auto f2 = [](double x){std::cout << "f double";};

//lambda      
//auto factorial = [](int x)->int{return x == 0 ? 1 : x * factorial(x - 1);};
std::function factorial = [&](int x){return x == 0 ? 1 : x * factorial(x - 1);};
対策:具名lambdaという新しい特性を追加します.
注意:次のC++コードには、予想される言語の新しい特性が含まれています.コンパイラではサポートされていません.
//  lambda    
[]f(int x){std::cout << "f int";};
[]f(double x){std::cout << "f double";};

//  lambda     
[]factorial(int x)->int{return x == 0 ? 1 : x * factorial(x - 1);};

関連リンク
Generic (Polymorphic) Lambda http://cpp-next.com/files/2012/09/N3418.pdf