2016-05-30 11 views
3

Ich habe einige Code mit tiefer C++ 11 Variadic Vorlage magische Verwendung. Ich verwende spezielle Klassen, um Teile des Vorlagenbaums zu identifizieren, die ich "Tags" nenne. Jedes Tag hat eine eindeutige Nummerkennung. Ich muss einen Weg finden, wie Kennungen für den Zugriff auf Tag-Zugriff Vorlage Argumente mit partiellen Typ Wissen

Hier einige kleine Beispiel ist:

#include <string> 
#include <iostream> 

template <unsigned long ID, typename PARAM> 
class tag_ 
{ 
    //getter for ID. Better to exclude it. If possible - move to external helper 
    constexpr static unsigned long get_id() {return ID;} 
    //PARAM is used in some functions of this class 
}; 

//tag's declarations for future usage 
template<typename PARAM> 
using tag1 = tag_<1UL, PARAM>; 
template<typename PARAM> 
using tag2 = tag_<2UL, PARAM>; 
template<typename PARAM> 
using tag3 = tag_<3UL, PARAM>; 

//helper class that can iterate TAGS 
template <template<typename> class... TAGS> 
struct helper 
{}; 
template <template<typename> class TAG> 
struct helper<TAG> 
{ 
    static void print_tag(std::ostream& out) 
    { 
     out << std::string("Tag"); 
     out << TAG::get_id(); // Here I can't call: error: 'template<class> class TAG' used without template parameters 
    } 
}; 
template <template<typename> class TAG, template<typename> class... TAGS> 
struct helper<TAG, TAGS...> 
{ 
    static void print_tag(std::ostream& out) 
    { 
     out << std::string("Tag"); 
     out << TAG::get_id(); // Here I can't call: error: 'template<class> class TAG' used without template parameters 
     out << std::string(", "); 
     helper<TAGS...>::print_tag(out); 
    } 
}; 

//this class uses tags for some processing 
template <template<typename> class... TAG_LIST> 
class tagged 
{ 
public: 
    void test1(std::ostream& out) 
    { 
     out << std::string("This function works good"); 
    } 
    void test2(std::ostream& out) 
    { 
     helper<TAG_LIST...>::print_tag(out); 
    } 
}; 

// this class is re-defined for some types of T 
template<typename T, typename PARAM> 
class usage 
{ 
public: 
    void test1(std::ostream& out) 
    { 
     details.test1(out); 
    } 
    void test2(std::ostream& out) 
    { 
     details.test2(out); 
    } 

    T details; 
    PARAM params; 
}; 

//endpoint 
struct finish{}; 

//definition for future usage 
template<template<typename> class T1, template<typename> class T2, template<typename> class T3, typename PARAM> 
using multitag = usage<tagged<T1, T2, T3>, PARAM>; 

int main(int argc, const char* argv[]) 
{ 
    // this way I am construction my objects tree 
    multitag<tag1, tag2, tag3, tag1<tag2<tag3<finish>>>> tmp; 
    tmp.test1(std::cout); // ok 
    std::cout << std::endl; 
    tmp.test2(std::cout); //compile error. I want to get "Tag1, Tag2, Tag3" printed 
    std::cout << std::endl; 
} 
+1

'TAG :: GET_ID()' funktioniert nicht, da TAG keine vollständige Typ ist. Gemäß Ihrer Definition von tag1/tag2/tag3 müssen Sie einen Template-Parameter namens PARAM angeben, aus welchem ​​Grund auch immer Sie ihn dort abgelegt haben. Nur indem ich eine Änderung an 'TAG :: get_id()' machte und die Memberfunktion 'get_id' öffentlich machte, konnte ich kompilieren. – Arunmu

Antwort

2
multitag<tag1, tag2, tag3, tag1<tag2<tag3<finish>>>> tmp; 

Dies ist Ihre Definition für tmp, übergeben Sie nur in tag1, die eine Template-Typ ist alias

template<typename PARAM> 
using tag1 = tag_<1UL, PARAM>; 

jedoch sein Template-Parameter PARAM ist nicht vorgesehen. Also, wenn Sie es verwenden möchten,

out << TAG::get_id() 

Sie sollten es einen Parameter geben, zum Beispiel

out << TAG<dummy>::get_id(); 

dummy etwas, zum Beispiel sein kann,

class dummy{}; 

http://coliru.stacked-crooked.com/a/bb1d924dc3d5b774

+0

Das ist, was ich gesucht habe. Die Idee, irgendeinen Typ (sogar Void-Funktionen) anstelle des PARAM zu verwenden, löst das Problem in meinem Fall. Ich habe keinen Zugriff auf die richtige PARAM-Struktur in meiner Funktion und kann sie nicht als Parameter übergeben. Auf diese Weise produzieren weniger Code, aber es ist akzeptabel für mich – Evgeniy

1

Das nächste, was Sie bekommen können, ist eine Spezia zu deklarieren lisierung für jeden tagX:

template <template <typename> class TAG> struct tag_id; 

template <> struct tag_id<tag1> : std::integral_constant<unsigned long, 1UL> {}; 
template <> struct tag_id<tag2> : std::integral_constant<unsigned long, 2UL> {}; 
template <> struct tag_id<tag3> : std::integral_constant<unsigned long, 3UL> {}; 
out << tag_id<TAG>{}; 

DEMO

+0

Vielen Dank für Ihre Antwort. Sieht so aus, als wäre dieser Code vorzuziehen, da er besser entworfen wurde. Aber in meinem Fall bevorzuge ich eine zusätzliche Struktur als PARAM-Argument, da ich keine Spezialisierung für jedes Tag deklarieren möchte – Evgeniy

Verwandte Themen