2017-03-28 5 views
2

Ci-dessous est extrait de cppref:Existe-t-il un cas d'utilisation typique qui doit utiliser `is_detected_v`?

#include <experimental/type_traits> 

template<class T> 
using copy_assign_t = decltype(std::declval<T&>() = std::declval<const T&>()); 

struct Meow { }; 

using namespace std::experimental; 

int main() 
{ 
    static_assert(is_detected_v<copy_assign_t, Meow>, 
     "Meow should be copy assignable!"); // version 1 

    static_assert(is_copy_assignable_v<Meow>, 
     "Meow should be copy assignable!"); // version 2 
} 

est-il une différence entre version 1 et version 2?

Y a-t-il un cas d'utilisation typique qui doit utiliser is_detected_v?

+2

Le cas d'utilisation pour cela est SFINAE, pas d'erreurs matérielles. Si vous voulez une erreur dure, la solution la plus directe est bien. –

Répondre

3

std::is_detected peut être utilisé comme bloc de construction pour std::is_copy_assignable. Si vous souhaitez vérifier l'assignabilité de la copie, vous devez utiliser std::is_copy_assignable. Si vous avez besoin de vérifier l'existence d'une opération personnalisée/fonction membre, std::is_detected vous donne un moyen facile de le faire.

template<class T> 
using foo_detector = decltype(std::declval<T&>().foo()); 

static_assert(!is_detected_v<foo_detector, Meow>, "Meow shouldn't have `.foo()`!"); 

Un cas d'utilisation exemple réaliste est l'unification des différentes API:

template<class T> 
using clean_detector = decltype(std::declval<T&>().clean()); 

template<class T> 
using clear_detector = decltype(std::declval<T&>().clear()); 

template <typename T> 
auto clear(const T& x) -> std::enable_if_t<is_detected_v<has_clean, T>> 
{ 
    x.clean(); 
} 

template <typename T> 
auto clear(const T& x) -> std::enable_if_t<is_detected_v<has_clear, T>> 
{ 
    x.clear(); 
} 

Exemple d'utilisation:

struct Foo { void clean(); }; 
struct Bar { void clear(); }; 

int main() 
{ 
    Foo f; Bar b; 
    clear(f); 
    clear(b); 
} 
0

est détecté, vous permet de déterminer si une substitution causerait l'échec.

Cela vous permet d'écrire un trait (ad hoc ou non) qui exprime un contrôle SFINAE.

Ces caractères peuvent être transmis, utilisés comme étiquettes et inversés.

Donc, je peux écrire can_foo facilement avec elle. Ensuite, je peux avoir deux surcharges, l'une si can_foo l'autre si !can_foo. Avec SFINAE traditionnel, écrire une surcharge valide si can_foo est facile; mais !can_foo est difficile.

Nous pouvons aussi tag dispatch ou l'utiliser pour constexpr si le calcul.

auto distance(Iterator A, Sentinal B){ 
    if constexpr (can_subtract_v<Sentinal&, Iterator&>){ 
    return B-A; 
    } else { 
    // count manually 
    } 
}