template parameter packs access Nth type and Nth element

后端 未结 5 984
广开言路
广开言路 2020-11-28 07:59

The following paper is the first proposal I found for template parameter packs.

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1603.pdf

At page 16,

5条回答
  •  执念已碎
    2020-11-28 08:49

    To get the Nth element from a pack you can write:

    Option 1

    Using tuple_element for getting the return type for the Nth element:

    template
    inline constexpr typename enable_if::type
    get(T&& t, Ts&&... ts) {
        return t;
    }
    
    template
    inline constexpr typename enable_if<(index > 0) && index <= sizeof...(Ts),
              typename tuple_element>::type>::type
    get(T&& t, Ts&&... ts) {
        return get(std::forward(ts)...);
    }
    
    // below is optional - just for getting a more readable compilation error
    // in case calling get with a bad index
    
    inline template
    constexpr bool index_ok() {
        return index >= 0 && index < sizeof...(Ts);
    }
    
    template
    inline constexpr
    typename enable_if(), T>::type
    get(T&& t, Ts&&... ts) {
        static_assert(index_ok(),
            "bad index in call to get, smaller than zero or above pack size");
        return t;
    }
    

    Option 2

    Without using tuple, relying on auto return type and specifically on C++14 decltype(auto) and on using enable_if as a template parameter and not as a return type:

    template::type* = nullptr>
    inline constexpr decltype(auto) get(T&& t, Ts&&... ts) {
        return std::forward(t); 
    }
    
    template 0 && index <= sizeof...(Ts))>::type* = nullptr>
    inline constexpr decltype(auto) get(T&& t, Ts&&... ts) {
        return get(std::forward(ts)...);
    }
    
    template
    inline constexpr bool index_ok() {
        return index >= 0 && index < (long long)sizeof...(Ts);
    }
    
    // block (compilation error) the call to get with bad index,
    // providing a readable compilation error
    template())>::type* = nullptr>
    inline constexpr decltype(auto) get(T&& t, Ts&&... ts) {
        static_assert(index_ok(),
            "bad index in call to get, smaller than zero or above pack size");
        return std::forward(t); // need to return something...
                                   // we hope to fail on the static_assert above
    }
    

    Usage example:

    template
    void resetElementN(Ts&&... ts) {
        get(std::forward(ts)...) = {}; // assuming element N has an empty ctor
    }
    
    int main() {
        int i = 0;
        string s = "hello";
        get<0>(i,2,"hello","hello"s, 'a') += get<0>(2);
        get<1>(1,i,"hello",4) += get<1>(1, 2);
        get<3>(1,2,"hello",i) += get<2>(0, 1, 2);    
        get<2>(1,2,s,4) = get<2>(0, 1, "hi");
        cout << i << ' ' << s << endl;    
        resetElementN<1>(0, i, 2);
        resetElementN<0>(s, 1, 2);
        cout << i << ' ' << s << endl;    
    
        // not ok - and do not compile
        // get<0>(1,i,"hello","hello"s) = 5;
        // get<1>(1,i*2,"hello") = 5;
        // get<2>(1,i*2,"hello")[4] = '!';
        // resetElementN<1>(s, 1, 2);
    
        // ok
        const int j = 2;
        cout << get<0>(j,i,3,4) << endl;
    
        // not ok - and do not compile
        // get<0>(j,i,3,4) = 5;    
    
        // not ok - and do not compile
        // with a readable compilation error
        // cout << get<-1>("one", 2, '3') << endl;
        // cout << get<3>("one", 2, '3') << endl;
    }
    

    Code
    Option 1: http://coliru.stacked-crooked.com/a/60ad3d860aa94453
    Option 2: http://coliru.stacked-crooked.com/a/09f6e8e155612f8b

提交回复
热议问题