2012-04-11 19 views
3

Ich schreibe gerade eine Interface-Klasse, die Zugriff auf interne Elemente einer komplexen Struktur als const- oder non-const-Referenzen ermöglichen soll. Die Idee ist, dass einigen Modulen Const-Zugriff gewährt wird und einigen Modulen Vollzugriff gewährt wird.Hinzufügen eines Const-Qualifikationsmerkmals zu einer Elementfunktion

Ich habe 'type_traits' 'std :: add_const' verwendet, um den Rückgabetyp der internen Memberfunktionen bedingt zu qualifizieren, leider kann ich mir keine Möglichkeit vorstellen, die Memberfunktionen bedingt als const oder non-const zu qualifizieren.

Ist das überhaupt möglich? Wenn das so ist, wie?

z.B:

template< typename T, bool isConst > 
struct apply_const 
{ 
    typedef T type; 
}; 

template<typename T> 
struct apply_const<T, true> 
{ 
    typedef typename std::add_const<T>::type type; 
}; 

template< bool isConst > 
const Interface 
{ 
    /// @brief get the TypeA member 
    typename apply_const<TypeA, isConst >::type& GetXpo3Container() // how do I conditionally add a const qualifier 
    { 
     return config_.type_a_member_; 
    } 

    typename apply_const<Profile, isConst >::type& GetProfile(unint32_t id) // qualifier ??? 
    { 
     return config_.profiles.get(id); 
    } 

    // .... lots more access functions 

    ConfigType config_; // the config 
}; 

Hinweis: der eigentliche Grund für die Trennung/Erstellen von 2 Versionen der Schnittstelle ist, dass sie den Zugriff auf verschiedene Instanzen von config Bereitstellung wird - eine, die beschreibbar und eines ist, das nicht der Fall ist. Das Subsystem, das entwickelt wird, ist ein eingebetteter Netconf Agent, der <running> und <candidate> Konfigurationen unterstützt.

+0

Verwenden Sie zwei Überladungen (eine Konstante und eine Nicht-Konstante), und verwenden Sie SFINAE, um jeweils nur eine davon zu aktivieren. – ildjarn

+0

2 Überladungen speichern tatsächlich nichts (wie unten angegeben).Das Ziel ist es, 2 Versionen von 'Schnittstelle' zur Verfügung zu stellen, wobei hier alle Mitgliedsfunktionen 'const' Referenzen zurückgeben und eine, wo alle Mitgliedsfunktionen nicht konstante Referenzen zurückgeben. Die Konstanz des Rückgabetyps ist kein Problem, sondern nur die Qualifizierung der Memberfunktion. Ich schätze, ich werde nur mit keiner Qualifikation für die Mitgliederfunktionen auskommen müssen, was kein allzu großes Problem darstellt. – mark

Antwort

5

Dies scheint am einfachsten mit einer Spezialisierung zu tun:

template< bool isConst > 
struct Interface; 

template <> 
struct Interface<false> 
{ 
    TypeA& GetXpo3Container() 
    { 
     return config_.type_a_member_; 
    } 
}; 

template <> 
struct Interface<true> 
{ 
    const TypeA& GetXpo3Container() const 
    { 
     return config_.type_a_member_; 
    } 
}; 

bearbeiten: obwohl ich nicht ganz sicher bin, was diese ergänzen. Wäre es nicht einfacher sein

struct Interface 
{ 
    TypeA::type& GetXpo3Container() 
    { 
     return config_.type_a_member_; 
    } 
    const TypeA::type& GetXpo3Container() const 
    { 
     return config_.type_a_member_; 
    } 
}; 

zu haben und verwenden const Interface angemessen wo? Oder ist das aus einem anderen Grund nicht möglich?

Edit 2: meine std::enable_if Verwendung war falsch, es ist jetzt weg.

+1

Dies führt zu einem schweren Fehler, nicht zu einem Soft-Fehler, da 'std :: enable_if :: type' nicht abhängig vom Umfang von' Interface' ist (dasselbe gilt für die andere Bedingung). –

+0

@LucDanton Ich habe gerade bearbeitet, als du bereits kommentiert hast, aber danke, und du hast recht :) – hvd

1

Sie können Ihre Vorlage für den Fall, dass spezialisieren isConst wahr ist, und machen das alle Elementfunktionen const in diesem Fall, während sie in der primären Vorlage nicht const verlassen.

Alternativ können Sie zwei Versionen der Elementfunktionen schreiben (eine const und eine nicht) und enable_if verwenden, um nur die entsprechende Überladung zu aktivieren.

1

können Sie SFINAE verwenden:

template<bool isConst> 
struct Interface 
{ 
    template< 
     bool Cond = isConst 
     , typename std::enable_if<!Cond, int>::type = 0    
    > 
    TypeA& 
    GetXpo3Container() const 
    { 
     return config_.type_a_member_; 
    } 

    template< 
     bool Cond = isConst 
     , typename std::enable_if<Cond, int>::type = 0 
    > 
    TypeA const& 
    GetXpo3Container() const 
    { 
     return config_.type_a_member_; 
    } 
}; 

Beachten Sie, dass die beiden Elemente Vorlagen vorgenommen werden müssen, und dass ich einen Standardparameter bin mit typename std::enable_if<Cond, int>::type zu zwingen, abhängig zu sein - im Rahmen der Klasse std::enable_if<isConst, int>::type ist nicht abhängig und wird daher einen Hard-Fehler net, wenn die Klasse instanziiert wird, während wir SFINAE wollen.

Der Standardparameter bedeutet jedoch, dass jemand z. Interface<true> f; TypeA& ref = f.GetXpo3Container<false>();. Wenn Sie das vermeiden wollen (zB Sie Benutzer nicht vertrauen nicht unbestimmten Bits Ihrer Schnittstelle mißbrauchen zu) hier ist eine andere Art und Weise das Mitglied type von std::enable_if abhängig wieder zu machen, die vielleicht besser geeignet ist, aber etwas obskur:

template<typename T, T Value, typename> 
struct depend_on_c { 
    static constexpr T value = Value; 
}; 

/* and in the scope of Interface: */ 
    template< 
     typename Dummy = void 
     , typename std::enable_if< 
      depend_on_c<bool, isConst, Dummy>::value 
      , int 
     >::type = 0 
    > 
    /* rest as before */ 
Verwandte Themen