[c++] std :: enable_if, um eine Elementfunktion bedingt zu kompilieren



Answers

Ich habe dieses kurze Beispiel gemacht, das auch funktioniert.

#include <iostream>
#include <type_traits>

class foo;
class bar;

template<class T>
struct check
{
    template<class Q = T>
    typename std::enable_if<std::is_same<Q, bar>::value, bool>::type test()
    {
        return true;
    }

    template<class Q = T>
    typename std::enable_if<!std::is_same<Q, bar>::value, bool>::type test()
    {
        return false;
    }
};

int main()
{
    check<foo> check_foo;
    check<bar> check_bar;
    if (!check_foo.test() && check_bar.test())
        std::cout << "It works!" << std::endl;

    return 0;
}

Kommentar, wenn Sie möchten, dass ich es ausarbeite. Ich denke, dass der Code mehr oder weniger selbsterklärend ist, aber dann habe ich es geschafft, damit ich falsch liege :)

Sie können es hier in Aktion here .

Question

Ich versuche, ein einfaches Beispiel zu erhalten, um zu verstehen, wie man std::enable_if . Nachdem ich diese Antwort gelesen hatte, dachte ich, es sollte nicht zu schwer sein, ein einfaches Beispiel zu finden. Ich möchte mit std::enable_if zwischen zwei Member-Funktionen wählen und nur eine davon verwenden.

Leider kompiliert das folgende nicht mit gcc 4.7 und nach stundenlangen Versuchen frage ich euch, was mein Fehler ist.

#include <utility>
#include <iostream>

template< class T >
class Y {

    public:
        template < typename = typename std::enable_if< true >::type >
        T foo() {
            return 10;
        }
        template < typename = typename std::enable_if< false >::type >
        T foo() {
            return 10;
        }

};


int main() {
    Y< double > y;

    std::cout << y.foo() << std::endl;
}

gcc meldet folgende Probleme:

% LANG=C make CXXFLAGS="-std=c++0x" enable_if
g++ -std=c++0x    enable_if.cpp   -o enable_if
enable_if.cpp:12:65: error: `type' in `struct std::enable_if<false>' does not name a type
enable_if.cpp:13:15: error: `template<class T> template<class> T Y::foo()' cannot be overloaded
enable_if.cpp:9:15: error: with `template<class T> template<class> T Y::foo()'

Warum löscht g ++ nicht die falsche Instantiierung für die zweite Elementfunktion? Gemäß dem Standard ist der std::enable_if< bool, T = void >::type nur vorhanden, wenn der boolesche Vorlagenparameter wahr ist. Aber warum betrachtet g ++ das nicht als SFINAE? Ich denke, dass die Überladungsfehlermeldung von dem Problem herrührt, dass g ++ die zweite Mitgliedsfunktion nicht löscht und glaubt, dass dies eine Überlastung sein sollte.




Von this Beitrag:

Standardschablonenargumente sind nicht Teil der Signatur einer Vorlage

Aber man kann so etwas machen:

#include <iostream>

struct Foo {
    template < class T,
               class std::enable_if < !std::is_integral<T>::value, int >::type = 0 >
    void f(const T& value)
    {
        std::cout << "Not int" << std::endl;
    }

    template<class T,
             class std::enable_if<std::is_integral<T>::value, int>::type = 0>
    void f(const T& value)
    {
        std::cout << "Int" << std::endl;
    }
};

int main()
{
    Foo foo;
    foo.f(1);
    foo.f(1.1);

    // Output:
    // Int
    // Not int
}



Der boolesche Wert muss von dem abgeleiteten Template-Parameter abhängen. Eine einfache Methode zur Behebung ist die Verwendung eines booleschen Standardparameters:

template< class T >
class Y {

    public:
        template < bool EnableBool = true, typename = typename std::enable_if<( std::is_same<T, double>::value && EnableBool )>::type >
        T foo() {
            return 10;
        }

};

Dies funktioniert jedoch nicht, wenn Sie die Elementfunktion überladen möchten. Stattdessen ist es am besten, TICK_MEMBER_REQUIRES aus der Tick Bibliothek zu verwenden:

template< class T >
class Y {

    public:
        TICK_MEMBER_REQUIRES(std::is_same<T, double>::value)
        T foo() {
            return 10;
        }

        TICK_MEMBER_REQUIRES(!std::is_same<T, double>::value)
        T foo() {
            return 10;
        }

};

Sie können auch ein eigenes Mitglied mit Makros wie folgt implementieren (nur für den Fall, dass Sie keine andere Bibliothek verwenden möchten):

template<long N>
struct requires_enum
{
    enum class type
    {
        none,
        all       
    };
};


#define MEMBER_REQUIRES(...) \
typename requires_enum<__LINE__>::type PrivateRequiresEnum ## __LINE__ = requires_enum<__LINE__>::type::none, \
class=typename std::enable_if<((PrivateRequiresEnum ## __LINE__ == requires_enum<__LINE__>::type::none) && (__VA_ARGS__))>::type



Links