SFINAE in für mehrere Fälle in bestimmter Reihenfolge



  • Hallo,

    ich habe folgendes Problem. Ich habe verschiedene Klassenhierarchien. Ich möchte eine bestimmte Information abfragen und im Prinzip kann ich diese auch bekommen. Leider wurde bei jeder Klasse eine andere Art der Implementierung gewählt und zudem unterstützen einige auch mehrere Arten...

    Bei der einen Klassenhierarchie erhalte ich die gesuchte Information durch den Aufruf einer Member-Funktion, bei einer anderen durch eine freie Funktion und bei wieder anderen ist es eine statische Variable der Klasse.

    Beispiel:

    struct A {}; std::string nameOfClass(const A &);
    struct B { char* className() const; };
    struct C { static std::string className; };
    

    Was ich zu implementieren Versuche:

    struct ClassNameGetter {
      template<class T>
      std::string className(const T &obj) {
          return obj.className;
      }
    
      template<class T>
      std::string className(const T &obj) {
          return obj.className();
      }
    
      template<class T>
      std::string className(const T &obj) {
          return nameOfClass(obj);
      }
    };
    

    Klar, im letzten Beispiel fehlt jetzt SFINAE. Allerdings habe ich große Probleme damit und weiß nicht wie ich es implementieren muss.

    Ich habe es mit std::enable_if und Templates wie diesem versucht:

    template<typename C>
    class has_className_method {
    private:
        template<typename T>
        static constexpr auto check(T*)
            -> typename std::is_same<decltype(std::declval<T>().className()), void>::type;
    
        template<typename>
        static constexpr auto check(...)
            -> std::false_type;
    
        typedef decltype(check<C>(0)) type;
    
    public:
        static constexpr bool value = type::value;
    };
    

    Vergleichbares habe ich für alle drei Fälle implementiert und scheinbar funktionieren diese Templates auch. Allerdings weiß ich nicht, wie ich diese in der ClassNameGetter Klasse einsetzen muss.

    Kann mir jemand helfen um auf die richtige Spur zu kommen?


  • Mod

    Leider wurde bei jeder Klasse eine andere Art der Implementierung gewählt und zudem unterstützen einige auch mehrere Arten...

    Hier liegt der Knackpunkt; wir müssen eine Rangfolge wählen, anhand der in mehrdeutigen Fällen unterschieden wird.

    Ungetestet - könnte etwa so aussehen:

    namespace detail {
      template <int i> struct rank : rank<i+1> {};
      template <> struct rank<30> {};
    
      template <typename T>
      auto getName(T const& t, rank<0>) -> decltype(t.className()) {
          return t.className(); }
      template <typename T>
      auto getName(T const& t, rank<1>) -> decltype(nameOfClass(t)) {
          return nameOfClass(t); }
      template <typename T>
      auto getName(T const& t, rank<2>) -> decltype(t.className) {
          return t.className; }
    }
    
    template <typename T>
    auto getName(T const& t) {return detail::getName(t, detail::rank<0>{});}
    

Anmelden zum Antworten