C++14stlintermediate
Transparent Operator Functors (std::less<>, std::greater<>)
C++14 · Modern Refined · Compiler flag: -std=c++14
Explanation
The standard comparison functors (`std::less`, `std::greater`, `std::equal_to`, etc.) now have a `void` specialization (e.g., `std::less<>`) that is a transparent comparator. It defines `is_transparent` and uses a templated `operator()`, enabling heterogeneous comparison without constructing temporaries. This is the enabler for heterogeneous lookup in associative containers.
Real-World Scenario
A sorted set of file paths stored as `std::string` needs frequent lookups from C-style strings received from a POSIX API. Using `std::less<>` lets the set compare directly against `const char*`.
Quick Snippet
snippet.cpp
#include <set>
#include <string>
#include <iostream>
#include <functional>
int main() {
std::set<std::string, std::less<>> files;
files.insert("/etc/hosts");
files.insert("/var/log/syslog");
files.insert("/tmp/data.csv");
// Lookup with const char* — no std::string temporary
if (files.count("/var/log/syslog"))
std::cout << "Found syslog\n";
// Works with std::greater<> too
std::set<int, std::greater<>> descending = {3, 1, 4, 1, 5};
for (int v : descending) std::cout << v << " "; // 5 4 3 1
std::cout << "\n";
}Full Example
transparent_functors.cpp
// CodeNebula - C++14 Example: Transparent Functors
// Compile: g++ -std=c++14 -Wall -Wextra -o example transparent_functors.cpp
// Demonstrates transparent (void-specialized) functors in C++14: std::less<>,
// std::greater<>, std::plus<>, etc. The void specialization deduces argument
// types automatically and enables heterogeneous comparison. Real-world use:
// generic algorithms, containers with mixed-type lookups, and reducing
// template boilerplate in comparator specifications.
#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>
#include <set>
#include <string>
int main()
{
// ------------------------------------------------------------------
// 1. std::less<> vs std::less<int> - type deduction
// ------------------------------------------------------------------
std::cout << "=== std::less<> (Transparent) ===" << std::endl;
// Old way: must specify type
std::less<int> old_less;
std::cout << " less<int>(3, 5) : " << std::boolalpha
<< old_less(3, 5) << std::endl;
// New way: type deduced, works with any comparable types
std::less<> new_less;
std::cout << " less<>(3, 5) : " << new_less(3, 5) << std::endl;
std::cout << " less<>(5.0, 3.0) : " << new_less(5.0, 3.0) << std::endl;
std::cout << " less<>(\"a\", \"b\") : " << new_less(std::string("a"), std::string("b")) << std::endl;
std::cout << std::endl;
// ------------------------------------------------------------------
// 2. All transparent comparison functors
// ------------------------------------------------------------------
std::cout << "=== All Comparison Functors ===" << std::endl;
int a = 10, b = 20;
std::cout << " a=" << a << ", b=" << b << std::endl;
std::cout << " less<>() : " << std::less<>()(a, b) << std::endl;
std::cout << " greater<>() : " << std::greater<>()(a, b) << std::endl;
std::cout << " less_equal<>() : " << std::less_equal<>()(a, b) << std::endl;
std::cout << " greater_equal<>(): " << std::greater_equal<>()(a, b) << std::endl;
std::cout << " equal_to<>() : " << std::equal_to<>()(a, b) << std::endl;
std::cout << " not_equal_to<>() : " << std::not_equal_to<>()(a, b) << std::endl;
std::cout << std::endl;
// ------------------------------------------------------------------
// 3. Transparent arithmetic functors
// ------------------------------------------------------------------
std::cout << "=== Arithmetic Functors ===" << std::endl;
std::cout << " plus<>()(3, 4) : " << std::plus<>()(3, 4) << std::endl;
std::cout << " minus<>()(10, 3) : " << std::minus<>()(10, 3) << std::endl;
std::cout << " multiplies<>()(5, 6): " << std::multiplies<>()(5, 6) << std::endl;
std::cout << " divides<>()(20, 4) : " << std::divides<>()(20, 4) << std::endl;
std::cout << " modulus<>()(17, 5) : " << std::modulus<>()(17, 5) << std::endl;
std::cout << " negate<>()(42) : " << std::negate<>()(42) << std::endl;
std::cout << std::endl;
// ------------------------------------------------------------------
// 4. Using with algorithms - no need to specify type
// ------------------------------------------------------------------
std::cout << "=== With STL Algorithms ===" << std::endl;
std::vector<int> nums = {5, 2, 8, 1, 9, 3, 7};
std::sort(nums.begin(), nums.end(), std::greater<>()); // descending
std::cout << " Sorted descending:";
for (int n : nums) std::cout << " " << n;
std::cout << std::endl;
std::sort(nums.begin(), nums.end(), std::less<>()); // ascending
std::cout << " Sorted ascending :";
for (int n : nums) std::cout << " " << n;
std::cout << std::endl;
std::cout << std::endl;
// ------------------------------------------------------------------
// 5. Mixed-type comparisons (the real power of transparent functors)
// ------------------------------------------------------------------
std::cout << "=== Mixed-Type Comparisons ===" << std::endl;
std::cout << " less<>()(1, 2.5) : " << std::less<>()(1, 2.5) << std::endl;
std::cout << " equal_to<>()(1, 1.0): " << std::equal_to<>()(1, 1.0) << std::endl;
std::cout << " plus<>()(1, 2.5) : " << std::plus<>()(1, 2.5) << std::endl;
std::cout << std::endl;
// ------------------------------------------------------------------
// 6. In containers for heterogeneous lookup
// ------------------------------------------------------------------
std::cout << "=== Container with Transparent Comparator ===" << std::endl;
std::set<std::string, std::less<>> words = {"hello", "world", "cpp14"};
// const char* lookup without std::string construction
std::cout << " find(\"world\") : "
<< (words.find("world") != words.end() ? "found" : "not found")
<< std::endl;
std::cout << " find(\"missing\"): "
<< (words.find("missing") != words.end() ? "found" : "not found")
<< std::endl;
return 0;
}
/*
Expected output:
=== std::less<> (Transparent) ===
less<int>(3, 5) : true
less<>(3, 5) : true
less<>(5.0, 3.0) : false
less<>("a", "b") : true
=== All Comparison Functors ===
a=10, b=20
less<>() : true
greater<>() : false
less_equal<>() : true
greater_equal<>(): false
equal_to<>() : false
not_equal_to<>() : true
=== Arithmetic Functors ===
plus<>()(3, 4) : 7
minus<>()(10, 3) : 7
multiplies<>()(5, 6): 30
divides<>()(20, 4) : 5
modulus<>()(17, 5) : 2
negate<>()(42) : -42
=== With STL Algorithms ===
Sorted descending: 9 8 7 5 3 2 1
Sorted ascending : 1 2 3 5 7 8 9
=== Mixed-Type Comparisons ===
less<>()(1, 2.5) : true
equal_to<>()(1, 1.0): true
plus<>()(1, 2.5) : 3.5
=== Container with Transparent Comparator ===
find("world") : found
find("missing"): not found
*/
Run command
g++ -std=c++14 -Wall -Wextra -o example transparent_functors.cpp