2012-09-22

Mike Spertus, Symantec

The purpose of this paper is to propose two extensions to `tuple:`

- Following the suggestion in [1], make
`tuple`s addressable by type as well as by index. - Make
`tuple`functorial in category-theoretical sense

Both of these are implemented

This is an idea
is inspired by Alexandrescu's *Modern C++ Design* [1]
`tuple` discussion.
Suppose we have a function `get_employee_info` that returns some employee information in a
`tuple<employee_id, salary, office>`. Saying something like `get<2>(get_employee_info(...)`
doesn't really make it that obvious that we are looking for the employee's
office. Furthermore, if we later become interested in returning another employee
attribute, we may need to adjust indexes all over the program.

This paper proposes allowing fields to be accessed by type, so the much clearer `get<office>(get_employee_info(...))` could be used
interchangeably with `get<2>(get_employee_info(...)`. The only technical
issue is what to do if a `tuple` contains repeated types. In that case, we require a compile error.
```
tuple<string, string, int> t("foo", "bar", 7);
string s = get<string>(t); // ERROR. Ambiguous access
```

Yes.
The approach in Loki suffices, because you can cast down to whichever `Holder<T>` you want. Also, I have my
Advanced C++ students implement type-addressable tuples each year.

The basic idea is simple. We want code like the following to work.
```
auto funcs = make_tuple(sqrt, strlen, atof);
auto vals = make_tuple(9, "foo", "7.3");
auto result = funcs(vals); // result is tuple<double, size_t, double>(3, 3, 7.3)
```

Of course, there is no need to limit oneself to ordinary functions. For example,
```
auto funcs = make_tuple(bind(std::multiplies<int, int>, _1, _1),
function(&string::size),
[](char const *cp)->double {
istringstream is(cp); double d; is >> d; return d;
});
auto vals = make_tuple(9, "foo", "7.3");
auto result = funcs(vals); // result is tuple<int, size_t, double>(81, 3, 7.3)
```

For a less artificial example, consider a function `get_order` that returns a `tuple<date,
map<item, int>>` representing
an order placed by a company. Suppose we want to convert this to a point on a
graph, where the *x* coordinate is the day number of the date and the y
coordinate is the total number of items in the order:
```
int days_from_epoch(date d);
int items_in_order(map<item, int> const &order_items)
{
// Just add up all the order counts
return accumulate(order_items.begin(), order_items.end(), 0,
[](int acc, pair<item, int> const &p) { return acc + p.second; });
}
auto point = make_tuple(days_from_epoch, items_in_order)(get_order(/* ... */));
```

Of course, the above example could have been done with a `pair` as easily as with a `tuple`, so
we also propose an analogous change for `pair`.

As an alternative to the definition of `tuple::operator()`, we could create a free
function `apply` in its place:
`auto result = apply(funcs, vals); // funcs, vals as above`

- Warning:
- This is a different meaning than proposed for
`apply`in N1483 [3]. This is also an important use case that we detailed in the EWG paper n3416. Briefly, that paper supports code like:`bool f(int, double, string); auto t = make_tuple(4, 3.14); bool result = f(t..., "foo");`

This provides a superset of the functionality of the functionality of`apply`in N1483

Yes. Please contact the author for a copy of the implementation

Change §20.4.1 [tuple.general] paragraph 2

// 20.4.2.6, element access:template <size_t I, class... Types> typename tuple_element<I, tuple<Types...> >::type& get(tuple<Types...>&) noexcept; template <size_t I, class... types> typename tuple_element<I, tuple<Types...> >::type&& get(tuple<Types...>&&) noexcept; template <size_t I, class... types> typename tuple_element<I, tuple<Types...> >::type const& get(const tuple<Types...>&) noexcept; template <typename T, class... Types> typename T& get(tuple<Types...>&) noexcept; template <typename T, class... types> typename T&& get(tuple<Types...>&&) noexcept; template <typename T, class... types> typename T const& get(const tuple<Types...>&) noexcept;

Change §20.4.2:

//20.4.2.3,tupleswap

void swap(tuple&) noexcept(see below);

//20.4.2.x,tuplefunctoriality

template<class.. UTypes> tuple<typename result_of<Types(UTypes)>::type...>operator()(tuple<UTypes...> &u); template<class.. UTypes> tuple<typename result_of<Types(UTypes)>::type...>operator()(const tuple<UTypes...> &u); template<class.. UTypes> tuple<typename result_of<Types(UTypes)>::type...>operator()(tuple<UTypes...> &u) const; template<class.. UTypes> tuple<typename result_of<Types(UTypes)>::type...>operator()(const tuple<UTypes...> &u) const; }; }

Add a new section §20.4.2.x [tuple.functorial]:

template<class.. UTypes> tuple<typename result_of<Types(UTypes)>::type...>operator()(tuple<UTypes...> &u);template<class.. UTypes> tuple<typename result_of<Types(UTypes)>::type...>operator()(const tuple<UTypes...> &u);template<class.. UTypes> tuple<typename result_of<Types(UTypes)>::type...>operator()(tuple<UTypes...> &u) const;template<class.. UTypes> tuple<typename result_of<Types(UTypes)>::type...>operator()(const tuple<UTypes...> &u) const;Requires:sizeof...(Types) == sizeof...(UTypes)and for all0 <= i < sizeof...(Types), the expressionget<i>(*this)(get<i>(u))is valid.

Returns:The result that would be achieved bymake_tuple(get<0>(*this)(get<0>(u)), get<1>(*this)(get<0>(1)),/* ... */).

Add the following to the end of §20.4.2.6 [tuple.elem]:

template <typename T, class... Types> T& get(tuple<Types...>& t) noexcept;Requires:The typeToccurs exactly once inTypes.... Otherwise, the program is ill-formed.

Returns:A reference to the element oftcorresponding to the typeTinTypes...template <typename T, class... Types> T&& get(tuple<Types...>&& t) noexcept;Effects:Equivalent to returnstd::forward<T&&>(get<i>(t));

Note:if aTin Types is some reference typeX&, the return type isX&, notX&&. However, if the element type is a non-reference typeT, the return type isT&&.template <typename T, class... Types> T& get(const tuple<Types...>& t) noexcept;Requires:The typeToccurs exactly once inTypes.... Otherwise, the program is ill-formed.

Returns:A const reference to the element oftcorresponding to the typeTinTypes...

[Note:Constness is shallow. If aTin Types is some reference typeX&, the return type isX&, notconst X&. However, if the element type is non-reference typeT, the return type isconst T&. This is consistent with how constness is defined to work for member variables of reference type.—end note]

[1] Alexandrescu, *Modern C++ Design: Generic Programming and Design Patterns
Applied*. Addison Wesley, 2001.

[2] Bar, *Category Theory. Lecture Notes for ESSLLI*,
http://www.ling.ohio-state.edu/~plummer/courses/winter09/ling681/barrwells.pdf.

[3] Gregor, Powell, Järvi, Typesafe variable-length function and template argument lists. Technical Report N1483=03-0066, ISO/IEC JTC 1, Information technology, Subcommittee SC 22, Programming language C++, 2003. www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1483.pdf.

[4] MacLane, *Categories for the Working Mathematician*, 2^{nd} edition.Springer-Verlag,
1997.