2017-07-24 8 views
0

Donc je fais un peu de devoirs où je dois écrire ma propre séquence entière en C++ 11 et y écrire quelques fonctions (print, concat, tri, etc.) mais j'ai un peu de mal à comprendre comment j'écrirais ces choses.Impression d'une séquence d'entiers en temps de compilation en C++ 11

template<typename T, typename Comp = std::less<int>> 
struct Facility{ 

    template<T ... Nums> 
    struct List{ 

     struct Element<T ... nums>{}; 

     template<unsigned num, T val, T ... rest> 
     struct Element{ 
      unsigned index = num; 
      T value = val; 
      Element<index-1, rest...> others; 
     }; 

     template<unsigned num, T val, T ... rest> 
     struct Element<0, val>{ 
      unsigned index = 0; 
      T value = val; 
     }; 

     static constexpr Element<sizeof...(Nums)-1,Nums...> elem = {}; 

     static void Print() 
     { 
      // Prints out the list 
     } 
    }; 

}; 

using IntList = typename Facility<int>::List<intlist...>; 

int main() 
{ 
    using List1 = IntList<1, 2, 3>; 
    List1::print() 
} 

Je voudrais juste savoir si je suis sur la bonne voie alors je ne me travaille pas dans une impasse. Je ne suis pas sûr à 100% sur le static print() et le membre static constexpr dans List, bien que je ne peux pas penser à aucun autre moyen de le faire fonctionner.

Répondre

0

Je ne comprends pas exactement ce que vous voulez obtenir et la signification de ce que vous avez fait (pourquoi Facility? Pourquoi List installation intérieure?).

Je viens de vous donner un exemple de la façon d'écrire Print() sans récursion, en utilisant un tableau utilisé (et la définition IntList, comme le suggère Yakk, se inspirant de std::integer_sequence)

#include <iostream> 
#include <functional> 

template <typename T, T ... Nums> 
struct IntList 
{ 
    static void Print (std::ostream & s = std::cout) 
    { 
     using unused = int[]; 
     (void)unused { 0, ((void)(s << Nums << ", "), 0)... }; 
     s << std::endl; 
    } 
}; 

int main() 
{ 
    using List1 = IntList<int, 1, 2, 3>; 
    List1::Print(); 
} 

Si vous pouvez utiliser C + +17 au lieu de C++ 11/C++ 14, vous pouvez écrire Print() sans le hack utilisé, déballer simplement Nums comme suit

static void Print (std::ostream & s = std::cout) 
    { (s << ... << (s << Nums, ", ")) << std::endl; } 

en ce qui concerne concat et trier, je supposons que vous voulez que la fonction membre renvoie (par exemple, la concat) un IntList avec une concaténation des deux listes de nombres.

L'un exemple simple concat peut être l'organe statique suivant pour IntList

template <T ... Nums2> 
static constexpr IntList<T, Nums..., Nums2...> 
    Concat (IntList<T, Nums2...> const &) 
{ return {}; } 

Vous pouvez écrire quelque chose comme

constexpr IntList<int, 1, 2, 3> l1; 
constexpr IntList<int, 4, 5, 6> l2; 

constexpr auto l3 = l1.Concat(l2); 

l3.Print(); // print 1, 2, 3, 4, 5, 6, 

Je vous laisse la fonction de tri exercice aussi simple :-)

+0

L'installation et la liste ont été fournies dans le dossier d'affectation. Des fonctions comme le tri, etc. doivent être fournies dans Facility, tandis que Print est la seule fonction dans List. J'ai réalisé que beaucoup de mon problème venait de penser que la liste était un objet réel, alors que j'aurais dû y penser comme un ensemble de structures créées par méta-fonctions chaînées. Je pense que je devrais aller bien d'ici. Merci beaucoup! – ozma

4

Ne pas inutilement imbriquer des types comme ça. Ecrivez une séquence <T,Ts...>.

Ne pas coupler les opérations au type. Écrire des opérations (queue, tête) à l'extérieur.

Inspirez-vous de std::integer_sequence<T,T...> en C++ 14.

Si vous avez besoin de cette interface que vous décrivez dans l'OP, écrivez-la plutôt en termes plats.

De loin le type le plus simple à écrire est le tri par fusion.

Exploitez std::integral_constant, qui est C++ 11. Ecrivez une métafonction qui prend un paramètre de modèle de modèle et une de vos listes entières, et passe chaque constante intégrale à comme type, et génère une liste de types template<class...Ts>struct types{}; en sortie. Appelez cela foreach_int

Ecrivez foreach_type, qui prend une liste de types et appelle un objet fonction sur chaque élément. Maintenant, l'impression est triviale. template<class list> void print_list(){ foreach_type(foreach_int< idenitity, list >{}, print{}); }template<cls T> void print(T && t}{std::cout<<t;}

Chacun d'entre eux est plus facile à raisonner, et les composer vous permet de "imprimer chacun".

Mais peut-être que je suis un peu fou.

+0

Désolé, pour être tout à fait honnête, j'ai du mal à comprendre la plupart de cela. Lorsque vous indiquez des types d'imbrication inutiles, voulez-vous dire Facility & List? Si c'est le cas, ceux-ci ont été fournis dans le cadre du code d'affectation. Que voulez-vous dire par le couplage des opérations au type ? Et pour clarifier, à plat, voulez-vous dire non-récursif? Comme enchaîner l'héritage dans les tuples? – ozma