SFINAE does not apply :(



  • Folgendes ist (wie zu erwarten war) Unsinn: (EDIT: Wie sich weiter unten herausstellt: ist doch kein Unsinn)

    template <typename T, typename Stub = mplex::char_<0> >
    struct takes_one {
        typedef char yes[1];
        typedef char no[2];
    
        template <typename C>
        static yes& test(typename C::template apply <Stub>*); 
    
        template <typename>
        static no& test(...);
    
        static const bool value = sizeof(test<T>(nullptr)) == sizeof(yes);
    };
    
    int main () {
        std::cout << takes_one <is_equal>::value;
    }
    

    Ist klar was ich versuche zu erreichen? (rausfinden wie viele Parameter apply akzeptiert ohne das hinterlegen zu müssen in is_equal).
    Ich habe die Vermutung dass das unmöglich ist, aber aus Hoffnung frage ich hier trotzdem.

    EDIT: erweiterbar auf unendliche viele Parameter wäre von da aus ja easy (mit variadics ohne limit)



  • hmm, die Frage ist für mich nicht so ganz einfach zu verstehen.
    Aber ich denke, apply ist ein Member Functiontemplate von is_equal?

    d.h. irgendwie so?:

    #include <iostream>
    
    struct is_equal
    {
        template <typename T>
        void apply(T)
        {}
    };
    
    struct is_equal2
    {
        template <typename T>
        void apply(T, T)
        {}
    };
    
    template <typename C, typename R, typename... P>
    constexpr unsigned cnt(R (C::*p)(P...))
    {
        return sizeof...(P);
    }
    
    template <typename T, typename Stub = char* >
    struct takes_one 
    {
        static const bool value = cnt(& T::template apply<Stub>) == 1;
    };
    
    int main () 
    {
        std::cout << takes_one<is_equal>::value << "\n";
        std::cout << takes_one<is_equal2>::value << "\n";
    }
    


  • Oh ja ups. So einfach ist es leider nicht.

    Beispiel:

    struct is_equal {
        constexpr static const int arity = 2; // <- will ich mir sparen
        template <typename T, typename U>
        struct apply {
           using type = typename std::is_same <T, U>::type;
        };
    };
    
    struct is_space {
        constexpr static const int arity = 1; // <- will ich mir sparen
        template <typename CharT>
        struct apply {
            using type = bool_ <CharT::value == ' ' || CharT::value == '\n'; //...more
        };
    };
    

    ideal application

    takes_one<is_space>::value // true
    takes_one<is_equal>::value // false
    takes_two<is_equal>::value // true
    takes_two<is_space>::value // false
    

    further expansion of principle

    takes<2, is_equal>::value // true
    

    Aber wenn das unmöglich ist mache ich es vermutlich so:

    template <unsigned Arity>
    struct functor {
        constexpr static const unsigned arity = Arity;
        // more stuff
    };
    
    struct is_equal : functor <2> {
        //...
    };
    


  • Dann verstehe ich allerdings nicht mehr, warum Deine Lösung ganz oben "Unsinn" sein soll 🙂

    Wenn ich die ausprobiere, dann funktioniert eigentlich alles.
    siehe http://coliru.stacked-crooked.com/a/074d432531546335



  • 😮

    g++ 4.9.2: error does not take 1 argument
    g++ 5.1.0: compiles
    clang 3.6.0: compiles

    😕

    Muss wohl noch auf mingw-w64 warten und bis dahin clang verwenden (ich will g++ und clang unterstützen (aber immer nur die neuste Version))

    EDIT: jupp, sieht jetzt so aus:

    std::cout << has_arity_v <is_equal, 1>::value << "\n"; // 0
    std::cout << has_arity_v <is_equal, 2>::value << "\n"; // 1
    std::cout << has_arity_v <is_space, 1>::value << "\n"; // 1
    std::cout << has_arity_v <is_space, 2>::value << "\n"; // 0
    

Log in to reply