0

I played around with C++17/C++1z features apply and invoke a bit Ultimately I wanted to use apply to the result of equal_range directly like this:

cout << apply(std::distance, data.equal_range(4)) << '\n';

That did not compile. I thought It was because equal_range returned a pair and not a tuple but as it turns out, that is not the case.

My larger example compiles everything if I use a Lambda instead of std::distance. When thinking about the reason for that I assume it has something to do with instantiating the template function distance. Hrm, a pity that this does not work without it, because I would have a hard time instantiating it with `std::distance::iterator>

#include <iostream>
#include <set>
#include <functional> // invoke
#include <experimental/tuple> // apply

using std::set; using std::cout;
using std::invoke;
using std::experimental::apply;

int main() {
  set<int> data { 1,2,3,4,5,6 };

  // the C++11-way, not possible in one line.
  auto r = data.equal_range(4);
  cout << std::distance(r.first, r.second) << '\n';

#if 0 // do not work
  cout << invoke(std::distance, r.first, r.second) << '\n';
  cout << apply(std::distance, r) << '\n';
  cout << apply(std::distance, make_tuple(r.first, r.second)) << '\n';
  cout << apply(std::distance, data.equal_range(4)) << '\n';
#endif

 // explicitly instantiate distance: intolerably cumbersome
 cout << apply(std::distance<set<int>::iterator>, data.equal_range(4)) << '\n';

  // using a lambda: too long for a single line
  auto d = [](auto b, auto e) { return std::distance(b, e); };
  cout << invoke(d, r.first, r.second) << '\n';
  cout << apply(d, r) << '\n';
  cout << apply(d, make_tuple(r.first, r.second)) << '\n';
  cout << apply(d, data.equal_range(4)) << '\n';
} 

Is there a nicer, more compact way to use apply and invoke with template functions like distance without explicit instantiation or lambda?

towi
  • 21,587
  • 28
  • 106
  • 187
  • `distance` is a function template, not a template function, which is the problem. (`distance::iterator>` would be an example of a template function.) – ildjarn Nov 13 '16 at 14:52
  • @ildjarn I see what you mean, i have to get my terminology straight. Ok, I know what a *function template* is, but what is a *template function* then, if not just a *function*? `std::distance` is a FT, why is `distance::iterator>` a TF and not just a F? Because it is instantiated from a FT? If so, is there a difference between a TF and an F? – towi Nov 13 '16 at 15:00
  • 2
    "*what is a template function then, if not just a function*" It is indeed just a function, but it ranks lower in overload resolution than a 'regular' function and is thus worth distinguishing. (In this case there is no overload set consisting of both functions and template functions, so it doesn't apply here.) – ildjarn Nov 13 '16 at 15:01
  • @ildjarn Oh, cool! Indeed, worth mentioning! Is the terminology important for classes too? *Template class* versus *class template*? – towi Nov 13 '16 at 15:04
  • The same logical distinction exists: `template class foo` is a class template, because it is a template, not a class. – ildjarn Nov 13 '16 at 15:14
  • That is not what I meant. Is it important to speak of `vector` as a *template class* and not just a *class*? there is no overload resolution going on here where distinction is important, right? – towi Nov 13 '16 at 15:24
  • I don't think it's a useful distinction for types, no (except that you can extract the class template from a template class using TMP, which you obviously cannot with a regular class). – ildjarn Nov 13 '16 at 15:25

1 Answers1

1
#define OVERLOADS_OF(...)\
  [](auto&&...args)->decltype(auto){\
    return __VA_ARGS__( decltype(args)(args)... );\
  }

now OVERLOADS_OF(std::distance) is a lambda that can be passed to std::apply.

I have seen at least one proposal to put this (in prettier syntax, and not macro based) into the standard; I do not know its status.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • very nice indeed. Only two drawbacks: a) uses a gnu extension, b) uses a macro. But well noted nonetheless. – towi Nov 15 '16 at 08:52
  • @towi what gcc extension? `__VA_ARGS__` is C99. – Yakk - Adam Nevraumont Nov 15 '16 at 11:55
  • Ok, then my google search for it showed me wrong info. I probably misinterpreted [this answer](https://stackoverflow.com/questions/5588855/standard-alternative-to-gccs-va-args-trick). – towi Nov 16 '16 at 10:15