Use std::tuple for template parameter list instead of list of types

后端 未结 2 1921
梦谈多话
梦谈多话 2021-01-13 13:07

I\'m trying to make a call to a templated function like this :

typedef std::tuple Instrument         


        
相关标签:
2条回答
  • 2021-01-13 13:24

    Your first solution is failing because the second overload to get is not visible at the point of its own return type declaration; to get around this you would need to separate out the return type computation into its own subprogram.

    The second solution is closer; the problem is that you're only inferring the template std::tuple, not its arguments. An easy way to infer variadic arguments (e.g. type arguments to tuple) is through an empty tag structure, requiring one extra level of indirection:

    template<typename T> struct type_tag {};
    
    class Cache {
        // ... (as above)
    
        template<typename... Ts> std::tuple<Ts...> get(type_tag<std::tuple<Ts...>>) {
            return get<0, Ts...>();
        }
    
    public:
        template<typename T> T get() {
            return get(type_tag<T>{});
        }
    };
    

    You should check to see whether you can write the solution using pack expansion instead of recursion, for example:

    template<typename T> struct type_tag {};
    
    class Cache {
        template<typename... Ts> std::tuple<Ts...> get(type_tag<std::tuple<Ts...>>) {
            return std::tuple<Ts...>{Ts{}...};
        }
    
    public:
        template<typename T> T get() {
            return get(type_tag<T>{});
        }
    };
    
    0 讨论(0)
  • 2021-01-13 13:46

    Here is what I came up with:

    #include <tuple>
    
    struct Cache;
    
    /* typename = std::tuple<...> */
    template<int, typename> struct cache_getter;
    /* typename = parameters from std::tuple<...> */
    template<int, typename...> struct tuple_walker;
    
    template<int I, typename... Ts> struct cache_getter<I, std::tuple<Ts...> > {
        static std::tuple<Ts...> get(Cache & c);
    };
    
    struct Cache {
    protected:
        template<int, typename...> friend struct tuple_walker;
    private:
        /* here T is a type from within a std::tuple<...> */
        template<int I, typename T> std::tuple<T> get_ex() {
            return std::tuple<T>();
        }
    public:
        /* here T is actually a std::tuple<...> */
        template<typename T> T get() {
            return cache_getter<0, T>::get(*this);
        }
    };
    
    /* since std::tuple_cat only accepts 2 std::tuples per call but we don't have control over the number of types in the passed in std::tuple, we'll need to chain our calls */
    template<typename...> struct my_tuple_cat;
    template<typename H, typename... T> struct my_tuple_cat<H, T...> {
        static auto cat(H h, T... t) -> decltype(std::tuple_cat(h, my_tuple_cat<T...>::cat(t...)))
        { return std::tuple_cat(h, my_tuple_cat<T...>::cat(t...)); }
    };
    template<typename T> struct my_tuple_cat<T> {
        static T cat(T t) { return t; }
    };
    
    /* this one is used to call Cache.get_ex<int I, typename T>() with incrementing values for I */
    template<int I, typename H, typename... T> struct tuple_walker<I, H, T...> {
        static std::tuple<H, T...> get(Cache & c) {
            return my_tuple_cat<std::tuple<H>, std::tuple<T...>>::cat(c.get_ex<I, H>(), tuple_walker<I + 1, T...>::get(c));
        }
    };
    template<int I, typename H> struct tuple_walker<I, H> {
        static std::tuple<H> get(Cache & c) {
            return c.get_ex<I, H>();
        }
    };
    /* this one will forward the types in std::tuple<...> to tuple_walker to get each tuple separately */
    template<int I, typename... Ts> std::tuple<Ts...> cache_getter<I, std::tuple<Ts...> >::get(Cache & c) {
        return tuple_walker<I, Ts...>::get(c);
    }
    
    int main(int argc, char ** argv) {
        Cache cache;
        typedef std::tuple<int, double, bool> InstrumentTuple;
        InstrumentTuple tuple = cache.get<InstrumentTuple>();
        return 0;
    }
    

    I hope this is worth something. I haven't done much in C++11 yet, so maybe this isn't an optimal solution.

    Proof that it compiles can be found here

    0 讨论(0)
提交回复
热议问题