How to avoid using the "indices trick" repeatedly? - c++

I have a class named memory_region, which is sort of like an untyped gsl::span (i.e. it's essentially a void* and a size_t), which I also use for type erasure. It thus has an as_span<T>() method.
With this class, I have a std::unordered_map<std::string, memory_region> my_map - which is used to pass type-erased spans between parts of my code which don't share headers, so they can't know about each others' types. The typical access to one of these looks like:
auto foo = my_map.at("foo").as_span<bar_t>();
This works just fine with code that has a fixed set of buffers and types and names. But - things get tricky when my code's buffers depend on a template parameter pack. Now, I've implemented a
std::string input_buffer_name(unsigned input_buffer_index);
function, so if I have an index sequence and my parameter pack I can do, for example
template<typename Ts..., std::size_t... Indices>
my_function(std::unordered_map<std::string, memory_region>& my map) {
compute_stuff_with_buffers(
my_map.at(input_buffer_name(Indices)).as_span<Ts>()...
);
}
(this is a variation on the infamous indices trick; note that the same type may appear more than once in the pack, so I can't "wrap the types in a tuple" and acces it by type.)
The thing is, though - my code doesn't have that index sequence in the template parameters; most of it is templated on just the parameter pack of types. So I find myself writing "helper functions/methods" all the time to be able to use that index sequence, e.g.:
template<typename Ts..., std::size_t... Indices>
my_function_helper(
std::unordered_map<std::string, memory_region>& my map
std::index_sequence<Indices...> /* unused */)
{
compute_stuff_with_buffers(
my_map.at(input_buffer_name(Indices)).as_span<Ts>()...
);
}
template<typename Ts...>
my_function(std::unordered_map<std::string, memory_region>& my map) {
my_function_helper(
my_map, std::make_index_sequence<sizeof...(Ts)> {}
);
}
What can I do instead, that will not involve so much code duplication?

In this case you can use simple pack expansion in the form of an array:
template<typename... Ts>
void my_function(std::unordered_map<std::string, memory_region>& my_map) {
using swallow = int[];
unsigned i = 0;
(void)swallow{0, (my_map.at(input_buffer_name(i++)).as_span<Ts>(), 0)...};
}
Demo
The pack expansion will be expanded in order ([temp.variadic]), and also evaluated in order (left to right) because we're using a braced initializer list (an unused integer array): [dcl.init.aggr]
When an aggregate is initialized by an initializer list [...] the elements of the initializer list are taken as initializers for the elements of the aggregate, in order.
Re:
But what if I need to use input_buffer_name(i) twice? e.g. if I need to use
{ input_buffer_name(index), my_map.at(input_buffer_name(index).as_span<Ts>()) }
I suppose we could take advantage of the fact that logical AND will sequence left to right ([expr.log.and]), and also a boolean can be promoted to int:
template<typename... Ts>
void my_function_v2(std::unordered_map<std::string, memory_region>& my_map) {
using swallow = int[];
unsigned i = 0;
(void)swallow{0, ((std::cout<< input_buffer_name(i) << std::endl, true) && (my_map.at(input_buffer_name(i++)).as_span<Ts>(), true))...};
}
Demo 2

Related

How can I build a constexpr vector of types which can append types?

My colleague challenged me to build a TypeVector, which is compile time vector-like container which can push_back types and delete types at compile time. Given a constexpr TypeVector you should be able to query back the actual type from an element of the TypeVector.
PSEUDOCODE EXAMPLE USAGE OF TypeVector:
consteval auto build_vector() {
TypeVector<2> x; //TypeVector of size 2
x.push_back(int);
x.push_back(float);
return x;
}
static constexpr auto my_vector = build_vector();
// Get type from first element of my_vector
typename retrieve_type<my_vector.get<0>()>::type some_variable = 0; // equivalent to int some_variable = 0;
// Get type from second element of my_vector
typename retrieve_type<my_vector.get<1>()>::type some_variable2 = 0.0f; // equivalent to float some_variable2 = 0.0f;
I think the best way to do this is to use std::array
The problem is that std::array cannot store types but needs to store values of the same type, so I am transforming types into values like so:
template <typename T>
struct TypeHash{
static constexpr char obj; // Create one obj per type
static constexpr char* value = &obj; // This will be different for each type
};
template <typename T>
static constexpr char* to_value = TypeHash<T>::value;
// Now I can do to_value<int> and to_value<float> to "store" the float and int as values of type const char*
// Example usage:
template <int N>
using TypeVector<N> = std::array<const char*, N>;
consteval auto some_func() {
TypeVector<2> x;
x[0] = to_value<int>;
x[1] = to_value<float>;
return x;
}
static constexpr auto first_type = some_func()[0];
The problem is reversing this operation: creating retrieve_type from the pseudocode.
I thought of creatingretrieve_type as a const char* to type map through template specialisations like so:
static constexpr auto first_type = some_func()[0]; // From above
template < const char* value> struct retrieve_type {};
template <> struct retrieve_type<to_value<int>> { using type = int; };
template <> struct retrieve_type<to_value<float>> { using type = float; };
// Now I can get the actual type from first type:
typename retrieve_type<first_type>::type y = 0; // int x = 0;
There are a few problems with this approach:
I have to create a retrieve_type specialisation for each existing type ( not a huge problem, I can handle this, but it is not ideal)
(Bigger problem) How can I create retrieve_type specialisations for templates??
template <typename T>
struct SomeTemplateClass {};
// How to create a specialisation of retrieve_type for all instantiations of SomeTemplateClass?
How can I make this work for types instantiated from a template? Can I avoid manually creating a retrieve_type specialisation for each and every type?
I am open to using any third party libraries / any compiler specific options.
Templates can be bijecticely mapped to types.
template<class T>
strict tag_t{using type=T;};
template<class T>
constexpr tag_t<T> tag={};
template<template<class...>class Z>
struct ztemplate{
template<class...Ys>
constexpr auto operator()(tag_t<Ys>...)const{
return tag<Z<Ys...>>;
}
};
This handles one category of templates.
If you solve the value to type map problem, you can solve the value to template problem. And with the above a template is just a stateless constexpr function object on type tags.
For non type template parameters, you need a different tag type and different stateless function.objects. For example, a template that takes an std integral constant type can wrap a template that takes an integer value, making it better behaved.
As for value to type, that is just a long slow verbose slog.
You can build a parse tree in a flat list of integers.
Each node has a value and a count of children, both constexpr. You grab the first value and map via tag dispatching to a tag type. If the number of elements is more than 1 then invoke the tag dispatched result with recursively evaluated type tags generated from the list of integers.
template<std::size_t I>
using index_t=std::integral_constant<std::size_t,I>;
template<std::size_t I>
constexpr index_t<I> index{};
constexpr tag_t<int> map_to_type(index_t<0>){return {};}
constexpr ztemplate<std::vector> map_to_type(index_t<1>){return {};}
constexpr auto make_type(){
constexpr int arr[]={1,0};
return map_to_type(index<arr[0]>)(map_to_type(index<arr[1]>));
}
constexpr auto tag=make_type();
decltype(tag)::type vec={1,2,3};
C++ is a statically typed language. This means that, at compile time, the type of every expression must be known. It also means that the fundamental properties of every type are known at compile-time. Those properties are also well-defined at the point of the type's definition and cannot be changed.
If you have some construct that stores types, and you want to extract a type from it such that you can do normal type-stuff with that "value" (declare variables of that type, etc), then you must do it in a way that works within the limitations of a statically typed language.
This means that the construct that stores those types must be a type. Not an object, an actual type. There is no getting around that fact: if you want to be able to do type-computations, in order for the result of that operation to be a type, the source of that operation must also be a type (constexpr functions get to play games where you can pass "types" around as parameter values through a wrapper object, but that's just a trick of template argument deduction; the primary computation itself is on types).
This means that a type, in this paradigm, is a value. But since C++ is statically typed, such types are immutable. Whatever properties are on a type at the point of that type's definition are the properties that exist on it at all points in the program.
Always.
As such, we have to treat type-values in a functional programming way. In particular, type-values are immutable "objects". Whatever value they have is the value they have.
It's like the number 2. You can increment the number 2, but this doesn't change "2". It creates a new number 3, which is different from 2. "2" still exists even after you incremented it.
You must treat type-values in the same way. If you have a type-value that represents a list of types, you cannot append to it. You can create a new type-value which contains the previous list of types plus the one you appended. But the old type-value list still "exists".
There is no other way in C++ to have "values" that represent types that can be extracted in some way. At least, not until C++ gets some form of reflection.
Your attempt to get around this with "hashes" is clever, but it simply moves the immutable data.
Instead of having an immutable list of types, you have an immutable registry of types. This registry must be finite. It also maps between numbers and types. And templates are not types; they are meta-functions which generate types. std::vector isn't a type; std::vector<int> is a type generated by the std::vector metafunction.
A mapping function between numbers and types cannot map to between numbers and type generation meta-functions. C++, being a statically typed language, doesn't allow that.
Your attempt to get around immutability is clever, but it's still immutable. You traded immutability of lists for immutability of the table that maps between numbers and types.
But this list is also something else: finite.
In C++, a template is a meta-function that generates stuff: functions, variables, or types. A "template type" isn't really a thing. std::vector isn't a type; it is a thing which generates types based on a set of parameters. std::vector<int> is a type, generated by the std::vector meta-function.
If you have a mapping between numbers and types, then it maps between numbers and types, not type-metafunctions. Just like if you have a function parameter that takes an int, that function cannot be made to take a function that returns an int (you could create a new function that does this, but nevermind that now).
As such, you cannot store "templates" in your mapping table. Or rather, you could either store templates with a specific parameter list, or store things that aren't templates. But you can't do both.
There are dozens of such libraries available in C++. Boost.Hana has type-list functionality, as do many other libraries. But they're all going to have the limitations of C++.
But you can do basic type retrieval on a std::tuple. std::tuple_element_t<I, tpl> gets the type of the Ith type in tpl, and std::tuple_size_v<tpl> computes the number of elements in tpl. And basic appending functionality isn't hard either:
template<typename Tpl, typename T>
struct append_tuple; //No definition.
template<typename ...Types, typename T>
struct append_tuple<std::tuple<Types...>, T>
{
using type = std::tuple<Types..., T>;
};
template<typename Tpl, typename T>
using append_tuple_t = typename append_tuple<Tpl, T>::type;
And no, you're not going to be able to (easily) map a string name to a type.

Parameter pack to parameter pack mapping

I want to remap a parameter pack to a different type parameter pack.
More precisely I have a function:
template<typename ...type_pack, typename Function = void(type_pack&&...)>
constexpr decltype(auto) zip(Function&& op, type_pack&&... pack)
{
static_for<0, N_lhs>([&](auto i)
{
op(pack[i]...);
});
return;
}
Basically I want to create a parameter pack of the results from applying the [] to the pack elements. Note that i here is an integral constant, and the static_for is compile time, you can assume that [] is constexpr. I do not have much control over op, so it expects a parameter pack and not a tuple.
Edit:
Seems like I was under the misunderstanding that op(pack[i]...) was causing the issue, when in fact this is a legal C++ construct (I thought it was illegal). So it seems like something was actually wrong with my static_for loop. My question was originally regarding op(pack[i]...) so I will keep it as is.
I prepared a more general example not using [] but a different arbitrary function just for a sanity check: https://godbolt.org/z/h8Hbbt
Is there a place in the standard where this pack expansion behaviour is mentioned - namely the fact that functions may be applied on top?
Basically I want to create a parameter pack of the results from applying the [] to the pack elements.
Do you mean something as follows?
template <typename ... type_pack,
typename Function = void(decltype(std::declval<type_pack>()[0])...)>
constexpr decltype(auto) zip(Function&& op, type_pack&&... pack)
{
/* ... */
}
Please, prepare a minimal but complete example (static_for, mainly) if you want a more tested answer.
A parameter pack can be expanded in terms of a pattern.
template <typename... T>
void test(T... t) {
(std::cout << ... << static_cast<int>(t));
}
Here it is exanded as a folding expression, but it works in the same way in a regular pack expansion. The pattern here is static_cast<int>(t) and it will expand to
std::cout << static_cast<int>(t1) << static_cast<int>(t2) << ... << static_cast<int>(tN);

Compile time sort of heterogenous tuples

I know it's possible to use the C++ type system to generate a sorted type list from an existing tuple type.
Examples of doing this can be found at:
https://codereview.stackexchange.com/questions/131194/selection-sorting-a-type-list-compile-time
How to order types at compile-time?
However, is it possible to do a compile-time sort of a heterogeneous tuple by value? For example:
constexpr std::tuple<long, int, float> t(2,1,3);
constexpr std::tuple<int, long, float> t2 = tuple_sort(t);
assert(t2 == std::tuple<int, long, float>(1,2,3));
My assumption is this is not possible, since you'd have to conditionally generate new tuple types based on the result of comparing values. Even if the comparison function uses constexpr, it would seem that this can't work.
However, an offhand comment from this answer indicates it somehow is possible to do this, just very difficult:
I lied. You can do it if the values and the compare function are
constexpr, but the code to pull it off will be huge and not worth the
time to write.
So is this comment correct? How could this even be conceptually possible, given the way the C++ type system works.
To preface the answer, it might be vastly more straightforward to use Boost.Hana. The prerequisite for Hana is that your comparison produces a compile-time answer. In your case, this would require a Hana tuple containing compile-time versions of these basic data types, similar to std::integral_constant. If it's acceptable to have your tuples' values encoded entirely in their types, Hana makes this trivial.
I believe it would be possible to do this directly once you can use a tuple as a non-type template parameter in C++20. Until then, you can get pretty close (live example):
int main() {
constexpr std::tuple<long, int, float> t(2,1,3);
call_with_sorted_tuple(t, [](const auto& sorted) {
assert((sorted == std::tuple<int, long, float>(1,2,3)));
});
}
As far as I know, it is impossible to return the sorted tuple directly; the callback approach is required because it is instantiated with every possible tuple type and only the correct one is actually run. This means there is significant compile-time overhead to this approach. The compile times grow quickly with small tuple size increases.
Now, how does this actually work? Let's get the magic out of the way—converting a runtime integral value into a compile-time one. This can fit well into its own header, and is shamelessly stolen from P0376:
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0376r0.html
#include <array>
#include <type_traits>
#include <utility>
// A function that invokes the provided function with
// a std::integral_constant of the specified value and offset.
template <class ReturnType, class T, T Value, T Offset, class Fun>
constexpr ReturnType invoke_with_constant_impl(Fun&& fun) {
return std::forward<Fun>(fun)(
std::integral_constant<T, Value + Offset>());
}
// Indexes into a constexpr table of function pointers
template <template <class...> class ReturnTypeDeducer,
class T, T Offset, class Fun, class I, I... Indices>
constexpr decltype(auto) invoke_with_constant(Fun&& fun, T index,
std::integer_sequence<I, Indices...>) {
// Each invocation may potentially have a different return type, so we
// need to use the ReturnTypeDeducer to figure out what we should
// actually return.
using return_type
= ReturnTypeDeducer<
decltype(std::declval<Fun>()(std::integral_constant<T, Indices + Offset>()))...>;
return std::array<return_type(*)(Fun&&), sizeof...(Indices)>{
{{invoke_with_constant_impl<return_type, T, Indices, Offset, Fun>}...}}
[index - Offset](std::forward<Fun>(fun));
}
template <class T, T BeginValue, T EndValue>
struct to_constant_in_range_impl {
// Instantiations of "type" are used as the Provider
// template argument of argument_provider.
template <class U>
struct type
{
template <template <class...> class ReturnTypeDeducer, class Fun, class Self>
static constexpr decltype(auto) provide(Fun&& fun, Self&& self) {
return invoke_with_constant<ReturnTypeDeducer, T, BeginValue>(
std::forward<Fun>(fun),
std::forward<Self>(self).value,
std::make_index_sequence<EndValue - BeginValue>());
}
U&& value;
};
};
Now one thing to note is that I use C++20's ability to give lambdas template parameters simply because compilers already support this and it makes turning index_sequences into parameter packs really easy. The long way to do this is available prior to C++20, but a bit of an eyesore on top of code that's already hard enough to get through.
The sort itself isn't too bad despite the tuple needing compile-time indices for std::get (unless you reuse the above magic, but all I have to say to that is yikes). You can change the algorithm as needed. You can even use a regular std::vector in C++20 and push indices onto the back. What I chose to do is generate a std::array containing the sorted-order indices of the tuple:
// I had trouble with constexpr std::swap library support on compilers.
template<typename T>
constexpr void constexpr_swap(T& a, T& b) {
auto temp = std::move(a);
a = std::move(b);
b = std::move(temp);
}
template<std::size_t I>
using index_c = std::integral_constant<std::size_t, I>;
template<typename... Ts>
constexpr auto get_index_order(const std::tuple<Ts...> tup) {
return [&]<std::size_t... Is>(std::index_sequence<Is...> is) {
std::array<std::size_t, sizeof...(Is)> indices{Is...};
auto do_swap = [&]<std::size_t I, std::size_t J>(index_c<I>, index_c<J>) {
if (J <= I) return;
if (std::get<I>(tup) < std::get<J>(tup)) return;
constexpr_swap(indices[I], indices[J]);
};
auto swap_with_min = [&]<std::size_t I, std::size_t... Js>(index_c<I> i, std::index_sequence<Js...>) {
(do_swap(i, index_c<Js>{}), ...);
};
(swap_with_min(index_c<Is>{}, is), ...);
return indices;
}(std::index_sequence_for<Ts...>{});
}
The main idea here is obtaining a pack of indices from 0 to N-1 and then dealing with each individually. Rather than trying to generate a second pack from I+1 to N-1, I took the easy road and reused the 0 to N-1 pack I already had, ignoring all out-of-order combinations when swapping. The dance with index_c is to avoid calling the lambdas via awkward lambda.template operator()<...>(...) syntax.
Now we have the indices of the tuple in sorted order and magic to convert one index to one with its value encoded in the type. Rather than build the magic to handle multiple values, I took the probably-suboptimal approach to build on the support for one at a time by making a recursive function:
template<typename... Ts, typename F, std::size_t... Converted>
constexpr void convert_or_call(const std::tuple<Ts...> tup, F f, const std::array<std::size_t, sizeof...(Ts)>& index_order, std::index_sequence<Converted...>) {
using Range = typename to_constant_in_range_impl<std::size_t, 0, sizeof...(Ts)>::template type<const std::size_t&>;
if constexpr (sizeof...(Converted) == sizeof...(Ts)) {
f(std::tuple{std::get<Converted>(tup)...});
} else {
Range r{index_order[sizeof...(Converted)]};
r.template provide<std::void_t>([&]<std::size_t Next>(index_c<Next>) {
convert_or_call(tup, f, index_order, std::index_sequence<Converted..., Next>{});
}, r);
}
}
I would have made this a lambda to avoid repeating captures, but as its recursive, it needs a workaround to call itself in lambda form. I'd be happy to hear of a good, constexpr-compatible solution for lambdas in this case that takes into account the fact that the lambda's template arguments differ each call.
Anyway, this is the use of the magic. We want to call this a total of N times, where N is the tuple size. That's what the if constexpr checks for, and finally delegates to the function passed from main, easily building a new tuple from the compile-time index order sequence. To recurse, we add on this compile-time index to a list we build up.
Finally, since what should have been a lambda is its own function, the function called from main is a simple wrapper that gets the index-order array and starts off the runtime-sequence-to-compile-time-sequence recursion with nothing converted to start:
template<typename... Ts, typename F>
constexpr void call_with_sorted_tuple(const std::tuple<Ts...>& tup, F f) {
auto index_order = get_index_order(tup);
convert_or_call(tup, f, index_order, std::index_sequence<>{});
}
I believe, it can not be done.
The essential part of any sorting would be to use tuple value in if constexpr context, but since function arguments are not constexpr, they can not appear in if constexpr.
And since tuples can't be non-type template arguments, template-based solution can't be implemented either. Unless we make tuple of type-encoded values (like std::integral_constant) I believe the solution is not available.
Return type cannot depend of value of parameters (even more as parameter cannot be constexpr) of a function, so
constexpr std::tuple<long, int, float> t1(2, 1, 3);
constexpr std::tuple<long, int, float> t2(3, 2, 1);
static_assert(std::is_same<decltype(tuple_sort(t1), decltype(tuple_sort(t2)>::value, "!");

Need help to understand template function with complex typename parameters

I'm examining a Stroustroup's book "C++ Programming 4th edition". And I'm trying to follow his example on matrix design.
His matrix class heavily depends on templates and I try my best to figure them out.
Here is one of the helper classes for this matrix
A Matrix_slice is the part of the Matrix implementation that maps a
set of subscripts to the location of an element. It uses the idea
of generalized slices (§40.5.6):
template<size_t N>
struct Matrix_slice {
Matrix_slice() = default; // an empty matrix: no elements
Matrix_slice(size_t s, initializer_list<size_t> exts); // extents
Matrix_slice(size_t s, initializer_list<size_t> exts, initializer_list<siz e_t> strs);// extents and strides
template<typename... Dims> // N extents
Matrix_slice(Dims... dims);
template<typename... Dims,
typename = Enable_if<All(Convertible<Dims,size_t>()...)>>
size_t operator()(Dims... dims) const; // calculate index from a set of subscripts
size_t size; // total number of elements
size_t start; // star ting offset
array<size_t,N> extents; // number of elements in each dimension
array<size_t,N> strides; // offsets between elements in each dimension
};
I
Here are the lines that build up the subject of my question:
template<typename... Dims,
typename = Enable_if<All(Convertible<Dims,size_t>()...)>>
size_t operator()(Dims... dims) const; // calculate index from a set of subscripts
earlier in the book he describes how Enable_if and All() are implemented:
template<bool B,typename T>
using Enable_if = typename std::enable_if<B, T>::type;
constexpr bool All(){
return true;
}
template<typename...Args>
constexpr bool All(bool b, Args... args)
{
return b && All(args...);
}
I have enough information to understand how they work already and by looking at his Enable_if implementation I can deduce Convertible function as well:
template<typename From,typename To>
bool Convertible(){
//I think that it looks like that, but I haven't found
//this one in the book, so I might be wrong
return std::is_convertible<From, To>::value;
}
So, I can undersand the building blocks of this template function declaration
but I'm confused when trying to understand how they work altogather.
I hope that you could help
template<typename... Dims,
//so here we accept the fact that we can have multiple arguments like (1,2,3,4)
typename = Enable_if<All(Convertible<Dims,size_t>()...)>>
//Evaluating and expanding from inside out my guess will be
//for example if Dims = 1,2,3,4,5
//Convertible<Dims,size_t>()... = Convertible<1,2,3,4,5,size_t>() =
//= Convertible<typeof(1),size_t>(),Convertible<typeof(2),size_t>(),Convertible<typeof(3),size_t>(),...
//= true,true,true,true,true
//All() is thus expanded to All(true,true,true,true,true)
//=true;
//Enable_if<true>
//here is point of confusion. Enable_if takes two tamplate arguments,
//Enable_if<bool B,typename T>
//but here it only takes bool
//typename = Enable_if(...) this one is also confusing
size_t operator()(Dims... dims) const; // calculate index from a set of subscripts
So what do we get in the end?
This construct
template<typename ...Dims,typename = Enable_if<true>>
size_t operator()(Dims... dims) const;
The questions are:
Don't we need the second template argument for Enable_if
Why do we have assignment ('=') for a typename
What do we get in the end?
Update:
You can check the code in the same book that I'm referencing here
The C++ Programming Language 4th edition at page 841 (Matrix Design)
This is basic SFINAE. You can read it up here, for example.
For the answers, I'm using std::enable_if_t here instead of the EnableIf given in the book, but the two are identical:
As mentioned in the answer by #GuyGreer, the second template parameter of is defaulted to void.
The code can be read as a "normal" function template definition
template<typename ...Dims, typename some_unused_type = enable_if_t<true> >
size_t operator()(Dims... dims) const;
With the =, the parameter some_unused_type is defaulted to the type on the right-hand side. And as one does not use the type some_unused_type explicitly, one also does not need to give it a name and simply leave it empty.
This is the usual approach in C++ also found for function parameters. Check for example operator++(int) -- one does not write operator++(int i) or something like that.
What's happening all together is SFINAE, which is an abbreviation for Substitution Failure Is Not An Error. There are two cases here:
First, if the boolean argument of std::enable_if_t is false, one gets
template<typename ...Dims, typename = /* not a type */>
size_t operator()(Dims ... dims) const;
As there is no valid type on the rhs of typename =, type deduction fails. Due to SFINAE, however, it does not lead to a compile-time error but rather to a removal of the function from the overload set.
The result in practice is as if the function would have not been defined.
Second, if the boolean argument of std::enable_if_t is true, one gets
template<typename ...Dims, typename = void>
size_t operator()(Dims... dims) const;
Now typename = void is a valid type definition and so there is no need to remove the function. It can thus be normally used.
Applied to your example,
template<typename... Dims,
typename = Enable_if<All(Convertible<Dims,size_t>()...)>>
size_t operator()(Dims... dims) const;
the above means that this function exists only if All(Convertible<Dims,size_t>()... is true. This basically means the function parameters should all be integer indices (me personally, I would write that in terms of std::is_integral<T> however).
The missing constexprs notwithstanding, std::enable_if is a template that takes two parameters, but the second one is defaulted to void. It makes sense when writing up a quick alias to this to keep that convention.
Hence the alias should be defined as:
template <bool b, class T = void>
using Enable_if = typename std::enable_if<b, T>::type;
I have no insight into whether this default parameter is present in the book or not, just that this will fix that issue.
The assignment of a type is called a type alias and does what it says on the tin, when you refer to the alias, you're actually referring to what it aliases. In this case it means that when you write Enable_if<b> the compiler handily expands that to typename std::enable_if<b, void>::type for you, saving you all that extra typing.
What you get in the end is a function that is only callable if every parameter you passed to it is convertible to a std::size_t. This allows overloads of functions to be ignored if specific conditions are not met which is more a powerful technique than just matching types up for selecting what function to call. The link for std::enable_if has more information on why you would want to do that, but I warn beginners that this subject gets kinda heady.

Generate a std::tuple from standard container

Is there a portable way to generate a std::tuple (really a std::array) from the contents of a container? Such a tuple would allow std::apply to extract function arguments from a container.
My first attempt, using tail recursion, fails with compiler error: "recursive template instantiation exceeds maximum...".
I could not quite get my second attempt (std::for_each with a mutable lambda holding tuple) to compile with desired results.
I assume that something along the lines of how boost::mpl handles variadic metafunctions (ie magic using boost::preprocessor) could be made to work -- but that's so c++03. I'm hoping there's a better solution.
The function signature would look something like:
std::list<int> args_as_list = {1, 2, 3, 4};
auto tpl = args_as_tuple(args_as_list);
where type of tpl is std::array<int const, 4>.
Short answer: no, it is not possible.
Explanation: both std::tuple and std::array require compile-time information about number of elements. std::list or std::vector can provide only runtime information about elements count.
your args_as_tuple function would have to be a template, taking number of expected arguments as template argument (args_as_tuple<4>(args_as_list)).
Although having to put number of arguments as template argument seems harsh, but in case of your example it's is quite obvious - number of function arguments (function provided to std::apply) has to be known on compile-time as well.
For more generic code you could use: function-traits or code from this answer.
Or use std::array from begging instead of std::list (a lot of generic template code, but good compile time checks)
The number of elements in a std::tuple, or a std::array, is part of its type information. Therefore, your function args_as_tuple proposed above would have to be a template somehow, and each different possible size of the result is going to require a different instantiation of that template. Therefore, you cannot make a program that can support arbitrarily many sizes of tuples unless the code of that program is infinite (not possible).
If you only care about the range of values of int, say, you could instantiate the template 4 billion times, but then your executable is going to be at least 4 gigabytes large.
If you really only care about a few different sizes of vectors in your actual program, you could instantiate just those templates and write conversion code that cases out on the value of std::list::size() and calls the appropriate function (tedious).
But your exact code snippet
std::list<int> args_as_list = {1, 2, 3, 4};
auto tpl = args_as_tuple(args_as_list);
can never work in C++. Because, in C++ all variables have to have a known type determined at compile time. Even though you are using keyword auto, that auto has to get resolved at compile time to a fixed type, which means a fixed size if it's a tuple or array, no matter what sort of template shenanigans the expression args_as_tuple is doing.
Since my problem can't be solved, I solved a slightly different one which allowed me to move on.
I came up with a solution which allows me to extract arguments for a functor from a container. I am able to instantiate a eval_container with the functor I want evaluated, then pass the container to the resulting object.
#include <utility>
template <int N>
using Int = std::integral_constant<int, N>;
template <typename T>
struct arity : arity<decltype(&T::operator())> {};
template <typename T, typename RT, typename...Args>
struct arity<RT(T::*)(Args...) const>
{
// could enforce maximum number of arguments
static constexpr int value = sizeof...(Args);
};
template <typename F, int N = arity<F>::value>
struct eval_container
{
eval_container(F const& f) : f(f) {}
eval_container(F&& f) : f(std::move(f)) {}
template <typename Iter, typename I, typename...Args>
auto operator()(Iter&& iter, I, Args&&...args) const
{
// assert(iter != end)
auto&& arg = *iter++;
return (*this)(std::forward<Iter>(iter)
, Int<I()-1>{}
, std::forward<Args>(args)...
, arg);
}
template <typename Iter, typename...Args>
auto operator()(Iter&&, Int<0>, Args&&...args) const
{
// assert(iter == end)
return f(std::forward<Args>(args)...);
}
template <typename C>
auto operator()(C const& container) const
{
return (*this)(container.begin(), Int<N>{});
}
F f;
};
}