Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Transparent Operator Functors

Visual Studio 2013 Preview supports a C++14 feature called (according to this page) "Transparent Operator Functors". I'm not clear on what that means. The nearest C++14 proposal I found is this, but I'm not sure if it's the same thing: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3421

I'm looking for a more clear explanation of what it is, why it's an improvement, and maybe a snippet demonstrating its use.

like image 653
GravityWell Avatar asked Jul 19 '13 02:07

GravityWell


1 Answers

The transparent operator functors proposal is there as a way to have generalised functors that are located in <functional>. I personally believe the proposal itself has a very good example that would help illustrate the need for it. However I'll go ahead and try to explain it as well.

Suppose you have a function, a very basic function mind you:

template<typename T, typename U> auto less_than(T&& t, U&& u) -> decltype(std::forward<T>(t) < std::forward<U>(u)) {     return std::forward<T>(t) < std::forward<U>(u); } 

However you want to use this generalised function in the <algorithm> header. You have two options, to make it a struct functor:

struct MyLessThanFunctor {     template<typename T, typename U>     auto operator()(T&& t, U&& u) -> decltype(std::forward<T>(t) < std::forward<U>(u)){         return std::forward<T>(t) < std::forward<U>(u);     } }; 

Or in C++14, to make a polymorphic lambda:

[](auto&& t, auto&& u) -> decltype(auto) {      return std::forward<decltype(t)>(t) < std::forward<decltype(u)>(u);  } 

Both are very verbose when used in an algorithm like so:

int main() {     std::vector<int> v = {112,12,1281271,1919101,29181,412,1 };     std::sort(std::begin(v), std::end(v), MyLessThanFunctor()); // one     std::sort(std::begin(v), std::end(v), [](auto&& t, auto&& u) -> decltype(auto) {          return std::forward<decltype(t)>(t) < std::forward<decltype(u)>(u);      }); } 

This proposal aims to make it more compact and generalised by doing this instead:

std::sort(std::begin(v), std::end(v), std::less<>()); 

This gives you perfect forwarding and solves issues with truncation or problems that arise from changing the container but not the underlying type appointed by the container as mentioned by the paper.

Suppose you have a non-generalised functor:

struct Functor {     bool operator()(uint32_t a, uint32_t b) {         return a < b;     } }; 

And you use it with your std::vector<uint32_t> and it works all fine, but you forget about your functor not being generalised and use it with your std::vector<uint64_t>. Can you see the issue that has arisen? The elements will be truncated before being compared which is probably not what the user wanted. Generalised functors solve this issue for you before they arise.

like image 189
Rapptz Avatar answered Oct 02 '22 20:10

Rapptz