2017-09-08 5 views
1

Ich habe ein Problem wie dieses habe ich Kompilierung zu machen versuche:Templat Erste Template-Funktion Erklärung richtig

#include <vector> 
#include <array> 

struct Test 
{ 
    template <template <typename...> class Container, typename T, typename... Args> 
    void SetData(const Container<T, Args...>& data) 
    { 
     // compiles for vector but not array 
     // 'void Test::SetData(const Container<T,Args...> &)': could not deduce template argument for 'const Container<T,Args...> &' from 'std::array<float,3>' 

    } 
}; 


int main() 
{ 
    Test test; 
    std::vector<int> vector{ 1,2,3 }; 
    std::array<float, 3> arr{1.0f, 2.0f, 3.0f}; 

    test.SetData(vector); 
    test.SetData(arr); 

    return 0; 
} 

Im Grunde brauche ich eine Funktion Signatur, die jeder willkürlichen STL-Container aufnehmen kann (genauer gesagt std::vector und std::array) und ich brauche den Typ T sichtbar in der Funktion auch (dh int oder float in diesem Fall). Die anderen Typen (Allokator oder Größe) ist mir egal.

Was ist die korrekte Signatur?

+0

Sie werden nicht in der Lage sein, eine Vorlage bekommen sie alle als 'std :: array' nehmen verwendet einen nicht-Typ Template-Parameter. – NathanOliver

+0

@KaiserJohaan - Antwort verbessert: Definition des Typs in 'isCnt' mit einem anderen Namen für' type' (das auch von 'std :: true_type' und' std :: false_type' übernommen wird), sagen wir 'containedType', ist es möglich um den SFINAE-Aktivierungs-/Deaktivierungsteil zu vereinfachen, der an "T" arbeitet, und die Verwendung von "std :: enable_if" mit dem Rückgabetyp zu vermeiden. – max66

Antwort

0

Was ist die korrekte Signatur?

Soweit ich weiß, ist es nicht möglich, eine einzige korrekte Signatur zu schreiben, um alle Container und nur Container abzufangen.

aber wenn man eine Art Züge schreiben akzeptieren, die sagen, wenn ein Typ ist ein Container und extrahieren Sie die enthaltenen Typ (erfordern eine generische Version, eine partielle Spezialisierung für std::vector und ähnliche typename ... Container und eine Spezialisierung für std::array, andere Spezialisierungen können hinzugefügt werden) wie die folgende isCnt

template <typename> 
struct isCnt : public std::false_type 
{ }; 

// std::array case 
template <template <typename, std::size_t> class C, 
      typename T, std::size_t N > 
struct isCnt<C<T, N>> : public std::true_type 
{ using containedType = T; }; 

// other container case 
template <template <typename ...> class C, 
      typename T0, typename ... Ts> 
struct isCnt<C<T0, Ts...>> : public std::true_type 
{ using containedType = T0; }; 

Sie setData() konstruieren können als

Vorlage folgt :: containedType> Leere SetData (C const & Daten) { // Code hier }

Beachten Sie, dass setData() ist SFINAE aktiviert (oder deaktiviert) durch T = isCnt<C>::containedType, ist, dass nur für Container zur Verfügung.

Nachstehend ist ein voll funktionierendes Beispiel

#include <array> 
#include <vector> 
#include <iostream> 
#include <type_traits> 

template <typename> 
struct isCnt : public std::false_type 
{ }; 

// std::array case 
template <template <typename, std::size_t> class C, 
      typename T, std::size_t N > 
struct isCnt<C<T, N>> : public std::true_type 
{ using containedType = T; }; 

// other container case 
template <template <typename ...> class C, 
      typename T0, typename ... Ts> 
struct isCnt<C<T0, Ts...>> : public std::true_type 
{ using containedType = T0; }; 

struct Test 
{ 
    template <typename C, typename T = typename isCnt<C>::containedType> 
    void SetData (C const & data) 
    { 
     if (std::is_same<T, int>::value) 
     std::cout << "- int case" << std::endl; 
     else if (std::is_same<T, float>::value) 
     std::cout << "- float case" << std::endl; 
    } 
}; 

int main() 
{ 
    Test test; 
    std::vector<int> vector{ 1,2,3 }; 
    std::array<float, 3> arr{ { 1.0f, 2.0f, 3.0f } }; 

    test.SetData(vector); // print "int case" 
    test.SetData(arr); // print "float case" 
    //test.SetData(0); // compilation error 
}