Transparent Operator Functors

c++, c++11, c++14, visual-studio-2013

Solution

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.

Problem

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.

Original source