2016-07-26 13 views
0

Nehmen Sie zum Beispiel den folgenden Code:Wie Übergeben Vorlagen Vorlagenparameter zu Vorlagenklasse ohne den zugrunde liegenden Vorlagenparameter?

// Say I have this class defined in some other file 
class Foo; 

// This class will act as a wrapper for an integer map 
// to function pointers, which will create type TFoo objects 
// depending on the given input (in this case a "const char*" 
template<class TFoo> 
struct Bar 
{ 
    typedef TFoo foo_t; 
    typedef TFoo (*get_foo_f_t)(const char*); 
    typedef std::unordered_map<int, get_foo_f_t> foo_handler_map_t; 

    Bar(const foo_handler_map_t& handlers) 
     : handlers_(handlers) 
    { 
    } 
    ~Bar() 
    { 
    } 

    const foo_handler_map_t& handlers_; 
}; 

// Now, this class will receive an _object_ of type 
// "const Bar<T>&", which will have an already initialized 
// map of integers to function pointers, different 
// functions will be called with different input values 
// via the public method, "action()". 
template<class TFoo, const Bar<TFoo>& CBar> 
class Quux 
{ 
    public: 
     Quux() 
      : bar_(CBar) 
     { 
     } 
     ~Quux() 
     { 
     } 

     TFoo action(int a, const char* x) 
     { 
      auto it = this->bar_.handlers_.find(a); 
      if (it == this->bar_.handlers_.end()) 
      { 
       // no handler defined for int `a' 
       return TFoo(); 
      } 
      // i.e. CBar.handlers_[a](x) 
      return it->second(x); 
     } 

    private: 
     const Bar<TFoo>& bar_; 
}; 


// Here is how the map of integers to function pointers 
// will be initialized... 
static std::unordered_map<int, Foo (*)(const char*)> handlers 
{ 
    { 0, _hdl_0 }, // _hdl_* functions defined in different file 
    { 1, _hdl_1 }, 
    { 2, _hdl_2 } 
}; 
// And then passed to a "const Bar<T>" type object here 
const Bar<Foo> bar (handlers); 


int main() 
{ 
    // --> HERE IS WHAT I WANT TO CHANGE <-- 
    Quux<decltype(bar)::foo_t, bar> quux; 
    // ------------------------------------- 

    // Example (trivial) use of the 'quux' object 
    std::cout << quux.action(0, "abc").baz() << std::endl; 
    std::cout << quux.action(1, "def").baz() << std::endl; 
    std::cout << quux.action(2, "ghi").baz() << std::endl; 

    return 0; 
} 

Beachten Sie, dass die ‚Quux‘ Klasse nimmt zwei Template-Parameter - eine, die auch ein Template-Parameter für die ‚Bar‘ Klasse ist, und ein Verweis auf eine Vorlage Objekt vom Typ const Bar<T>, wobei T irgendeine Klasse ist, die mit 'Foo' in Beziehung steht. Ich möchte in der Lage sein, Folgendes zu tun statt:

Quux<bar> quux; 

Hinweis: ‚bar‘ ist ein Objekt vom Typ Bar<Foo>, aber es sollte auch jeder Bar<T> Typ sein kann.

Ist das möglich? Ich dachte, dass vielleicht so etwas wie unten als eine schnelle Abhilfe verwendet werden könnte, aber ich kann nicht herausfinden, was anstelle von /* ??? */ zu setzen:

template<const Bar</* ??? */>& CBar> 
using Nuff = Quux<decltype(CBar)::foo_t, CBar> 

Nuff<bar> nuff; 


EDIT

Ich bin einen Verweis auf ein Objekt an 'Quux' als Vorlagenparameter übergeben, weil das Kopieren ineffizient wäre (denke ich), anstatt eine Kopie des gesamten foo_handler_map_t Objekts zu erstellen. Ich möchte nur in der Lage eine Reihe von Objekten des Typs zu haben const Bar<T>, die global in einigen Namensraum definiert sind, und in der Lage Objekte ‚Quux‘ wie so zu initialisieren:

namespace blah 
{ 
std::unordered_map<int, /* funcptr type 0 */> _funcmap_0 { ... } 
std::unordered_map<int, /* funcptr type 1 */> _funcmap_1 { ... } 
... 

const Bar<Foo0> FSET0 (_funcmap_0); 
const Bar<Foo1> FSET1 (_funcmap_1); 
... 
} 

int main() 
{ 
    Quux<blah::FSET0> a; 
    Quux<blah::FSET1> b; 

    ... 

    return 0; 
} 

... und ich weiß nicht möchte es als Konstruktorargument übergeben.

+0

Was ist das 'template & CBAR>' ? Da Sie angeben, dass es kompiliert wird, denke ich, dass es genau wie ein Zeiger auf ein externes Objekt gültig ist. Aber was ist der Zweck hier, was versuchst du zu erreichen? –

+2

Es wäre schön, wenn Sie Ihr Beispiel stark reduzieren können. Bitte geben Sie den minimalen Code an, den wir benötigen, um Ihre Frage zu stellen! – Klaus

+2

Dies ist im aktuellen C++ nicht möglich, wird einmal möglich sein [n4469] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4469.html) wird angenommen. –

Antwort

2

Die Kommentare sind sehr nützlich. Wenn Sie jedoch wünschen, die Anzahl der Vorlage Argumente zu reduzieren, können Sie die CBar als Argument an den Konstruktor übergeben:

template<class TFoo> 
class Quux 
{ 
public: 
    Quux(const Bar<TFoo>& CBar) 
     : bar_(CBar) 
    {} 

    ~Quux() 
    {} 

    TFoo action(int a, const char* x) 
    { 
     auto it = this->bar_.handlers_.find(a); 
     if (it == this->bar_.handlers_.end()) 
     { 
     return TFoo(); 
     } 
     return it->second(x); 
    } 

private: 
    const Bar<TFoo>& bar_; 
}; 

und eine Funktion definieren, um eine Instanz von Quux zu erstellen:

template <typename TFoo> 
auto make_Quux(const Bar<TFoo>& bar) 
{ 
    return Quux<TFoo>(bar); 
} 

dann in main(), können Sie make_Quux() verwenden:

int main() 
{ 
    auto quux = make_Quux(bar); 
    //... 
} 
+2

Ja, ich verstehe nicht, warum jemand ein Template-Argument für die Referenz verwenden würde, wodurch für jede übergebene Referenz ein ganz anderer Typ instanziiert wird ... Ihr Beispiel ändert jedoch die Semantik der Klasse. Sie sollten es wahrscheinlich bearbeiten, um tatsächlich zu reflektieren, was das OP tut, d. H. Das erste Template-Argument und Dinge, die darauf basieren, behalten. Beachten Sie auch, dass 'make_ *' -Funktionen in C++ 17 überflüssig werden, da Konstruktoren in der Lage sein werden, Template-Argumente ihrer Klassen anzugeben (was Funktionen derzeit können). –