When to use the “identity” tmp trick?

前端 未结 2 892
感情败类
感情败类 2020-12-13 20:15

I have seen this meta function used, but never really understod why and in what context it is required. Can someone explain it with an example?

template <         


        
2条回答
  •  感情败类
    2020-12-13 20:51

    Trick #1

    Prevents template argument deduction:

    template 
    void non_deducible(typename identity::type t) {}
    
    non_deducible(1);      // error
    non_deducible(1); // ok
    
    template 
    void first_deducible(T a, typename identity::type b) {}
    
    first_deducible(5, 'A'); // ok
    

    Trick #2

    Disables unsafe/unwanted implicit deduction guides (c++17):

    template 
    struct smart_ptr {
        smart_ptr(typename identity::type* ptr) {}
    };
    
    smart_ptr{new int[10]};  // error
    smart_ptr{new int}; // ok
    

    Trick #3

    Makes defining type-traits (and other metafunctions) easier:

    template 
    struct remove_pointer : identity {};
    
    template 
    struct remove_pointer : identity {};
    

    Trick #4

    Can be used for tag dispatching:

    void foo(identity>) {}
    void foo(identity>) {}
    
    template 
    void bar(T t) {
        foo(identity{});
    }
    

    Trick #5

    Can be used for returning types:

    template 
    constexpr auto foo() {
        if constexpr (I == 0)
            return identity{};
        else
            return identity{};
    }
    
    decltype(foo<1>())::type i = 3.14f;
    

    Trick #6

    Helps to specialize functions accepting a forwarding-reference:

    template 
    void foo(T&& t, identity>) {}
    
    template 
    void foo(T&& t) { foo(std::forward(t), identity>{}); }
    
    foo(std::vector{});
    

    Trick #7

    Provides alternative syntax for declaring types, e.g. pointers/references:

    int foo(char);
    identity::type* fooPtr = &foo; // int(*fooPtr)(char)
    
    identity::type& strRef = "foo"; // const char(&strRef)[4]
    

    Trick #8

    Can be used as a wrapper for code expecting nested T::type to exist or deferring its evaluation:

    struct A {};
    struct B { using type = int; };
    
    std::conditional, A, identity>::type::type; // float
    std::conditional, B, identity>::type::type; // B
    

    Trick #9

    In the past, it used to serve as a workaround for a missing scope operator from the decltype() specifier:

    std::vector v;
    identity::type::value_type i;
    // nowadays one can say just decltype(v)::value_type
    

    The identity utility is proposed to be added to c++20:

    namespace std {
        template 
        struct type_identity { using type = T; };
    
        template 
        using type_identity_t = typename type_identity::type;
    }
    

提交回复
热议问题