2016-07-18 15 views
3

Ich programmiere einige Klassen, in die ich Abhängigkeiten über class Vorlage Parameter injizieren.Statisch Abfragen einer statischen Membervariable, die möglicherweise nicht vorhanden ist, als Standard?

In einigen Fällen haben oder können die Abhängigkeitsklassen statische consxpr-Member haben, die einige ihrer spezifischen Merkmale deklarieren. Im Fall des folgenden Beispiels können Klassen, die ein Renderer "Konzept" implementieren, eine statische Contexproline-Variable y_axis_bottom_up definieren, um anzugeben, dass sie vertikale Koordinaten erwarten, die in Aufwärtsrichtung wachsen.

Ich könnte natürlich eine Anforderung machen, dass alle Renderer-Implementierungen dieses Boolean-Member bereitstellen, aber ich würde lieber einen Standardwert im Abfrageausdruck definieren.

Da ich diese Informationen verwenden muss, um weitere Vorlagen zu parametrisieren, muss dieser Abfrageausdruck conetexpr sein.

Ich dachte, dass ich die Lösung hatte, als ich this stackoverflow answer fand, aber als ich versuchte, es auf meine Bedürfnisse anzuwenden, scheiterte ich.

Hier ist der - nicht funktionierende - minimale Testcode, den ich mir ausgedacht habe. Die zweite Ausgangsleitung sollte "1" heißen, aber beide Ausgänge sind "0".

Jede Hilfe wäre willkommen.

#include <iostream> 
#include <type_traits> 

template<class Config, typename = void> 
struct vertical_axis_bottom_up 
{ 
    static constexpr bool value = false; 
}; 

template<class Config> 
struct vertical_axis_bottom_up<Config, decltype(Config::Renderer::y_axis_bottom_up)> 
{ 
    static constexpr bool value = Config::Renderer::y_axis_bottom_up; 
}; 

struct Dummy_renderer {}; 

struct Config1 
{ 
    using Renderer = Dummy_renderer; 
}; 

struct Dummy_renderer_2 
{ 
    static constexpr bool y_axis_bottom_up = true; 
}; 

struct Config2 
{ 
    using Renderer = Dummy_renderer_2; 
}; 

int main(int /*argc*/, char * /*argv*/[]) 
{ 
    std::cout << "Default value for Config::Renderer::y_axis_bottom_up : " << vertical_axis_bottom_up<Config1>::value << std::endl; 
    std::cout << "Explicit value for Config::Renderer::y_axis_bottom_up: " << vertical_axis_bottom_up<Config2>::value << std::endl; 

    std::cout << "Press RETURN to terminate" << std::endl; 
    char ch; std::cin >> std::noskipws >> ch; 

    return -1; 
} 
+0

@BaummitAugen: fixed - danke – JPNotADragon

+0

@BaummitAugen: sollte das Zitat am Ende :-) – JPNotADragon

+0

gelesen haben kann ich nicht einen Weg finden außer Kraft zu setzen (zB über Vererbung), Ich denke also, mit der Einschränkung, die Klassen nicht zu ändern, bleibt die Option, die Anwesenheit des Mitglieds zu erkennen. –

Antwort

3

Diese ausgiebig in der Standardbibliothek durchgeführt wird, ist allocator_traits ein gutes Beispiel. Hier ist die Grundidee:

#include <iostream> 
#include <type_traits> 


template <class T, class = void> 
struct MyTrait 
{ 
    static constexpr bool foo = false; 
}; 

template <class T> 
struct MyTrait<T, std::enable_if_t<std::is_same<const bool, decltype(T::foo)>::value>> 
{ 
    static constexpr bool foo = T::foo; 
}; 

struct Class1 { 

}; 

struct Class2 { 
static constexpr bool foo = true; 
}; 


int main() 
{ 
    std::cerr << MyTrait<Class1>::foo; 
    std::cerr << MyTrait<Class2>::foo; 
} 

Im Grunde ist dies ein Trick sehr ähnlich dem void_t Trick (google, wenn Sie nicht vertraut sind). Wenn die Vorlagenklasse ein Mitglied des richtigen Typs bereitstellt, wird dieses Mitglied ausgewählt. Wenn nicht, fällt es auf falsch zurück. Wenn Sie also auf das foo Merkmal über MyTrait zugreifen, sind Sie garantiert dafür da.

Arbeitsbeispiel: http://coliru.stacked-crooked.com/a/d73f3674d0c53e53

+1

Ich dachte, ich hätte diese Variante ausprobiert, aber offensichtlich habe ich einen Fehler gemacht, weil das perfekt funktioniert. Vielen Dank! – JPNotADragon