2016-03-23 7 views
2

Ich habe ein Problem mit Typeigenschaften in C++. Ich bin es gewohnt, SFINAE-Prüfungen durchzuführen, um sicherzustellen, dass eine Funktion existiert oder nicht. Ich möchte jedoch eine Eigenschaft haben, die erkennen kann, ob eine Klasse eine bestimmte statische Funktion des Template-Elements besitzt.Typeigenschaft für statische Funktion der Elementvorlage

Dieses Beispiel erklärt mein Problem. Stellen wir uns vor, dass die Funktion doMake einen Funktionszeiger als Parameter und ihre Argumente als Paket akzeptiert.

struct A { 
    static A construct(int mA, double mB) { 
     return A{mA, mB}; 
    } 

    int a; 
    double b; 
}; 

struct B { 
    // silly but some of my code need this 
    template<typename T> 
    static B construct(int mA, T mB) { 
     return B{mA, mB}; 
    } 

    int a; 
    double b; 
}; 

struct Container { 
    // function (1) 
    template<typename T, typename... Args, 
     typename std::enable_if<has_template_construct<T>::value, int>::type = 0> 
    T make(Args&&... args) { 
     return doMake(&T::construct<Args...>, std::forward<Args>(args)...); 
    } 

    // function (2) 
    template<typename T, typename... Args, 
     typename std::enable_if<has_construct<T>::value, int>::type = 0> 
    T make(Args&&... args) { 
     return doMake(&T::construct, std::forward<Args>(args)...); 
    } 

    // function (3) 
    template<typename T, typename... Args, 
     typename std::enable_if<!has_construct<T>::value, int>::type = 0> 
    T make(Args&&... args) { 
     return T{std::forward<Args>(args)...}; 
    } 
}; 

// ... 

int main() { 
    Container c; 
    auto a = c.make<A>(1, 5.7); // would call (2) 
    auto b = c.make<B>(2, 5.8); // would call (1) 
    auto d = C.make<float>(4.f); // obviously call the last 
    return 0; 
} 

Ich weiß, wie has_construct zu implementieren, aber ich bin ganz verloren, wie has_template_construct zu implementieren. Kann mir jemand Hinweise geben? Danke!

+0

Warum nicht Ausdruck SFINAE wie 'declltype (& T :: Template-Konstrukt )'? – Jamboree

Antwort

3

Mit experimentellen is_detected können Sie tun:

template<class T> 
using construct_t = decltype(&T::construct); 

template<class T, typename...Ts> 
using template_construct_t = decltype(&T::template construct<Ts...>); 

template <typename T> 
using has_construct = is_detected<construct_t, T>; 

template <typename T, typename...Ts> 
using has_template_construct = is_detected<template_construct_t, T, Ts...>; 

Beachten Sie, dass in function1, müssen Sie verwenden has_template_construct<T, Args...>::value (,Args... hinzugefügt).