2017-11-28 5 views
1

Ich versuche, eine Druckfunktion für meine Template-Klasse zu schreiben:C++ Template-Klasse Druckfunktion

struct ColumnKey; 

template <class Type, class Key = ColumnKey> 
class Column { 
protected: 
    std::shared_ptr<Type> doGet() { 
    std::lock_guard<std::mutex> lock(mutex_); 
    return std::make_shared<Type>(value_); 
    } 
    void doSet(const std::shared_ptr<Type> &value) { 
    std::lock_guard<std::mutex> lock(mutex_); 
    value_ = *value; 
    } 
private: 
    Type value_; 
    std::mutex mutex_; 
}; 

template<class... Columns> 
class Table : private Columns... { 
public: 
    template<class Type, class Key = ColumnKey> 
    std::shared_ptr<Type> get() { 
    return Column<Type, Key>::doGet(); 
    } 

    template<class Type, class Key = ColumnKey> 
    void set(const std::shared_ptr<Type> &value) { 
    Column<Type, Key>::doSet(value); 
    } 

    std::string get_table_row() { 
    return "hello_row"; 
    } 
}; 

ich eine Funktion get_table_row in Klasse Table, erstellen möchten, die columnA + "," + columnB + "," + ..

kehrt den ich versuche zu schreibe auf diese Weise, aber es kommt zu Kompilierungsfehlern. Kann jemand den Fehler in meiner Annäherung zeigen?

template <class Column<class Type, class Key = ColumnKey>> 
    std::string get_row() { 
     return std::to_string(*Column<Type, Key>::doGet()); 
    } 

    template <class Column<class Type, class Key = ColumnKey>, class... Columns> 
    std::string get_row() { 
     return (std::to_string(*Column<Type, Key>::doGet()) + "," + Columns.get_row()); 
    } 

Ich kämpfe um das zu tun, kann mich jemand führen?

+0

Sie können die Vorlagenargumente rekursiv durchlaufen, siehe [diese Antwort] (https://stackoverflow.com/a/12342686/948128) – piwi

+0

Mögliches Duplikat von [Wie drucke ich die Argumente einer Funktion mit aus eine variadische Vorlage?] (https://stackoverflow.com/questions/12342633/how-do-i-print-out-the-arguments-of-a-function-using-a-variadic-template) – piwi

+0

@piwi I denke, das ist etwas anders als das, was ich erreichen möchte. Ich habe auch 'Key', und ich möchte einen Wert zurückgeben. Außerdem möchte ich nur 'Tabelle , Spalte , Spalte >. Get_row()' aufrufen. Grundsätzlich ohne irgendwelche Argumente zu übergeben. – user3636955

Antwort

0

Sie fold expressions

template<typename T, typename K> 
struct Column 
{ 
    T val; 
}; 

template<typename FirstColumn, typename... Columns> 
struct Table : private FirstColumn, private Columns... 
{ 
    std::string get_table_row() 
    { 
     using std::to_string; 
     return (to_string(FirstColumn::val) + ... + ("," + to_string(Columns::val))); 
    } 
}; 

Sie für den Fall spezialisieren könnten verwendet werden soll wo gibt es null Spalten, wenn Sie einen Anwendungsfall dafür haben.

+0

Danke für die präzise Antwort. Es muss dann mit "-std = C++ 1z" auf MacOS kompiliert werden – user3636955

0

Hier ist eine Lösung, die möglicherweise funktioniert.

Die Struktur printer iteriert über die variadische Vorlage und rufen Tabelle :: für jede Art erhalten:

template <typename TableT> 
struct printer 
{ 
    printer(TableT& t): m_table(t) {} 

    template <typename T> 
    void impl(std::ostream& output) 
    { 
    using type = typename column_type<T>::type; 
    output << *m_table.template get<type>(); 
    } 

    template <typename First, typename Second, typename... Other> 
    void impl(std::ostream& output) 
    { 
    impl<First>(output); 
    impl<Second, Other...>(output); 
    } 

    template <typename... T> 
    std::string invoke() 
    { 
    std::ostringstream out; 
    impl<T...>(out); 
    return out.str(); 
    } 

    TableT& m_table; 
}; 

Ich schrieb ein Merkmal der Säule abzuleiten Type:

template <typename> struct column_type; 
template <template <typename, typename> class Column, typename Type, typename Key> 
struct column_type<Column<Type, Key>> 
{ 
    using type = Type; 
}; 

Um zu verwenden, Drucker, habe ich die Spalten Typen in einem Tupel gespeichert und entpacke es:

Die Struktur auspacken ruft den Drucker:

template <typename> struct unpack; 
template <typename... T> struct unpack<std::tuple<T...>> 
{ 
    template <typename TableT> 
    static std::string invoke(TableT& t) 
    { 
    printer<TableT> p(t); 
    return p.invoke<T...>(); 
    } 
}; 
0

Ihre get_row Member-Funktionen sind in der Tat schlecht ausgebildet. Wir müssen die Spalten rekursiv bearbeiten. Um dies zu tun, werden wir eine Hilfsklasse müssen (weil Funktionsschablonen nicht teilweise spezialisiert sein können), zusammen mit Merkmalen Helfer-Typ Ihre Column ‚s Key und Type Parameter abzuleiten:

template <typename> 
struct column_traits; 

template <typename Type, typename Key> 
struct column_traits<Column<Type, Key>> { 
    using type = Type; 
    using key = Key; 
}; 

template <typename...> 
struct TableRowPrinter; 

template <typename Col> 
struct TableRowPrinter<Col> { 
    template <typename TableT> 
    static std::string get_row(TableT& table) { 
     using col_traits = column_traits<Col>; 
     return std::to_string(
       *table.template get<typename col_traits::type, 
            typename col_traits::key>()); 
    } 
}; 

template <typename HeadCol, typename... Cols> 
struct TableRowPrinter<HeadCol, Cols...> { 
    template <typename TableT> 
    static std::string get_row(TableT& table) { 
     using col_traits = column_traits<HeadCol>; 
     return std::to_string(
        *table.template get<typename col_traits::type, 
             typename col_traits::key>()) + 
       ", " + TableRowPrinter<Cols...>::get_row(table); 
    } 
}; 

Jetzt, in der Table Klassenvorlage alles, was Sie tun müssen, ist die richtige Member-Funktion hinzuzufügen:

std::string get_row() { 
    return TableRowPrinter<Columns...>::get_row(*this); 
} 

Sie können ein funktionierendes Beispiel auf Coliru sehen.

Anmerkung: Ich habe nicht "sauber" die ungewöhnliche shared_ptr Nutzung ... Das ist ein anderes Thema ...