3 ms·
Obviously there's a whole section on comma folds that you didn't read. However, more importantly, there are things that you can't do without recursion. For ex
by mazieres 3y ago
Obviously there's a whole section on comma folds that you didn't read. However, more importantly, there are things that you can't do without recursion. For example, how would you implement the `index_string` function in the section on recursing over template parameters without using recursion?
- mgaunard 3y agoThere is zero need for template recursion here, or even templates at all. The functionality can be computed as a simple constexpr function. A string as a char template parameter pack is a textbook example of an antipattern.
- mazieres 3y agoActually not. Try to implement a compile-time initialized const char* that represents some compile-time value like sizeof(X) for some data structure X. You'll see that you need recursion. A place where this kind of pattern is useful is in having a generic accessor type for fields, and wanting to extend it to tuples. So for example accessor(x) might return x.field, and accessor.name might be "field." To make it work for tuples, you need a string for every possible tuple index. E.g.: template<typename T, size_t N> struct tuple_accessor; template<typename...T, size_t N> struct tuple_accessor<std::tuple<T...>, N> { constexpr decltype(auto) operator(auto &&t) const { return get<N>(std::forward<decltype(t)>(t)); } static constexpr const char *name = index_string<N>(); };
- mgaunard 3y agofor demonstration purposes only. #include <array> #include <tuple> constexpr std::array<char, 11> itos(unsigned n) { std::array<char, 11> s; unsigned i = 0; while (n) { s[i++] = '0' + (n % 10); n /= 10; } s[i] = '\0'; return s; } template<auto V> struct static_value { static constexpr auto value = V; }; template<class T, unsigned N> struct tuple_accessor; template<class...T, unsigned N> struct tuple_accessor<std::tuple<T...>, N> { static constexpr const char *name = static_value<itos(N)>::value.data(); };
- mazieres 3y agoYour constexpr function is not legal because it doesn't initialize all the array elements, even though the compiler might let you get away with it. That's easily fixed. More importantly, though, your static_value::value is not a const char *.
- mgaunard 3y agoThat restriction was lifted in 2020. tuple_accessor::name is a const char* which is what you asked for. static_value here is an implementation detail and the type of its members is irrelevant.
- planede 3y agoYou don't need recursion, but you do need a template, AFAIK. https://godbolt.org/z/o53o53W5r https://godbolt.org/z/o53o53W5r
- angiosperm 3y agoWhy does the <size_t ...Idxs> construct work, when we needed same_as<char>?
- planede 3y agoContext. I assume you mean something like `void foo(size_t ...Idxs)`, which indeed doesn't work. It can't work, as nothing indicates that this would be a template, and it should be at least templated on the size of the pack. <size_t ...Idxs> works because it introduces a pack that is a template parameter, so it naturally gets templated on the size of the pack (as well as on the values). I guess an other historical issue for the grammar is that without the parameter name, `void foo(size_t ...)` is already valid grammar, and is equivalent to `void foo(size_t, ...)`, a C-style variadic.