LINQ pour la compréhension de la liste en C ++, fournit une implémentation de LINQ pour C ++. Actuellement, il ne prend en charge que les plages C ++, mais il prend en charge les méthodes d'extension et de requête pour LINQ. Voici un exemple:
struct student_t
{
std :: string last_name ;
std :: vector < int > scores ;
} ;
std :: vector < student_t > students =
{
{ "Omelchenko" , { 97 , 72 , 81 , 60 } } ,
{ "O'Donnell" , { 75 , 84 , 91 , 39 } } ,
{ "Mortensen" , { 88 , 94 , 65 , 85 } } ,
{ "Garcia" , { 97 , 89 , 85 , 82 } } ,
{ "Beebe" , { 35 , 72 , 91 , 70 } }
} ;
auto scores = LINQ ( from ( student , students )
from ( score , student . scores )
where ( score > 90 )
select ( std :: make_pair ( student . last_name , score ) ) ) ;
for ( auto x : scores )
{
printf ( "%s score: %i n " , x . first . c_str ( ) , x . second ) ;
}Le code C ++ ci-dessus les sortira (oui, c'est le code C ++ ci-dessus):
Omelchenko score: 97
O'Donnell score: 91
Mortensen score: 94
Garcia score: 97
Beebe score: 91
Les extensions sont implémentées à l'aide du | Opérateur de tuyaux. Cela leur permet d'être appliqués à n'importe quelle gamme, sans nécessiter de handicaper d'une classe de base spéciale. Ainsi, les extensions peuvent fonctionner comme ceci:
vector< int > numbers = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 };
auto r = numbers
| linq::where([]( int x) { return x > 2 ; })
| linq::select([]( int x) { return x * x; });Les méthodes d'extension prises en charge sont:
La bibliothèque fournit également une classe range_extension , qui peut également être utilisée pour écrire vos propres extensions. Définissez d'abord la fonction comme une classe d'objets de fonction, comme ceci:
struct contains_t
{
template < class Range , class T >
bool operator ()(Range && r, T && x) const
{ return (r | linq::find (x)) != boost::end (r); };
};Puis initialisez l'extension en utilisant l'initialisation statique:
range_extension< contains_t > contains = {};Ensuite, l'extension peut être utilisée comme ceci:
if (numbers | contains( 5 )) printf( " We have a 5 " ); Toutes les requêtes LINQ doivent commencer par une from . Cela spécifie le nom de variable à utiliser pour les lambdas et le conteneur auxquels les requêtes seront appliquées. De plus, plusieurs from peuvent être utilisées.
struct student
{
std :: string name ;
std :: vector < int > grades ;
student ( ) { }
template < class Range >
student ( std :: string name , Range && r )
: name ( name ) , grades ( boost :: begin ( r ) , boost :: end ( r ) )
{ }
} ;
std :: vector < student > students =
{
student ( "Bob" , { 90 , 100 , 75 } )
student ( "Tom" , { 92 , 81 , 70 } )
student ( "Terry" , { 105 , 98 , 94 } )
} ;
// { 90, 100, 75, 92, 81, 70, 105, 98, 94 }
auto q = LINQ ( from ( s , students ) from ( g , s . grades ) select ( g ) ) ; La clause WHERE renvoie l'élément qui correspond au prédicat. Il est facultatif mais doit venir après une clause from la clause et doit être devant une clause select en cas de.
vector < int > v = { 1 , 3 , 4 , 5 } ;
// { 1, 3, 5 }
auto q = LINQ ( from ( i , v ) where ( i % 2 ) ) ;La clause Select applique une transformation aux éléments. Il est également facultatif, mais devrait être la toute dernière clause.
std :: vector < int > v = { 1 , 2 , 4 } ;
// { 3, 6, 24 }
auto q = LINQ ( from ( x , v ) select ( x * 3 ) ) ; La clause orderby vous permet de spécifier des éléments pour commander la plage. ascending ou descending peut également être précédé par le sélecteur afin de spécifier la direction de commande. La valeur par défaut est ascendante.
struct person
{
std :: string name ;
int age ;
person ( ) { }
person ( std :: string name , int age )
: name ( name ) , age ( age )
{ }
} ;
std :: vector < person > people =
{
person ( "Tom" , 25 ) ,
person ( "Bob" , 22 ) ,
person ( "Terry" , 37 ) ,
person ( "Jerry" , 22 )
}
// { "Jerry", "Bob", "Tom", "Terry" }
auto q = LINQ ( from ( p , people ) orderby ( p . age , descending p . name ) select ( p . name ) ) ; La clause group regroupe les éléments d'une séquence. Le premier paramètre est le sélecteur de clés, et le second est le sélecteur de valeur.
struct person
{
std :: string name ;
int age ;
person ( ) { }
person ( std :: string name , int age )
: name ( name ) , age ( age )
{ }
} ;
std :: vector < person > people =
{
person ( "Tom" , 25 ) ,
person ( "Bob" , 22 ) ,
person ( "Terry" , 37 ) ,
person ( "Jerry" , 22 )
}
auto q = LINQ ( from ( p , people ) group ( p . age , p . name ) ) ; Linq peut être facilement installé avec CGET:
cget install pfultz2/Linq
Cela installera automatiquement la dépendance à la surdication. La bibliothèque peut également être installée manuellement avec CMake.
find_package(Linq) est également disponible pour consommer linq à partir de cmake:
find_package(Linq)
target_linkq_libraries(yourLib linq::linq)
Pour un soutien complet, il nécessite Clang ou GCC et Boost. Il y a un support partiel pour Visual Studio. Visual Studio ne prend pas en charge le default_if_empty , group_by , group_join , join , order_by , select_many et then_by extensions, et il ne prend pas en charge orderby , group et imbriqué à partir de clauses. Peut-être que certains sorciers Visual Studio pourraient aider à trouver des solutions de contournement pour les bogues MSVC.
Multiples from instructions sont implémentées à l'aide de Lambdas imbriqués. Cependant, en raison d'un bogue dans MSVC 2010, les lambas imbriqués ne fonctionnent pas (cela devrait être corrigé dans MSVC 2012, mais je ne l'ai pas testé). S'il existe un moyen de mettre en œuvre des identifiants transparents en C ++, les lambdas imbriqués pourraient être évités.
De plus, les clauses let et join ne sont pas encore prises en charge. La clause into ne peut pas être prise en charge sans l'aide de lambdas polymorhpic.
Bsl-1.0