CodeNebula
C++17stladvanced

std::apply

C++17 · Practical Modern · Compiler flag: -std=c++17

Explanation

Calls a callable with the elements of a tuple unpacked as individual arguments. It bridges tuple-based data and function-call interfaces, making it easy to forward stored arguments.

Real-World Scenario

Invoke a database query function with parameters stored as a tuple from a prepared statement cache.

Quick Snippet

snippet.cpp
#include <tuple>
#include <functional>

auto args = std::make_tuple(std::string("users"), 42, true);
auto result = std::apply([](const std::string& table, int id, bool active) {
    return table + " WHERE id=" + std::to_string(id);
}, args);

Full Example

apply.cpp
// CodeNebula - C++17 Example: std::apply
// Compile: g++ -std=c++17 -Wall -Wextra -o example apply.cpp

// Demonstrates std::apply, which unpacks a tuple and passes its elements
// as individual arguments to a callable. This bridges tuple-based storage
// with regular function call syntax.

#include <iostream>
#include <tuple>
#include <string>
#include <functional>

// A simple function to call with tuple arguments
int add(int a, int b, int c)
{
    return a + b + c;
}

// A function taking mixed types
std::string format_person(const std::string& name, int age, double height)
{
    return name + " (age " + std::to_string(age) + ", " +
           std::to_string(height).substr(0, 4) + "m)";
}

struct Multiplier {
    int factor;
    int operator()(int x, int y) const { return factor * (x + y); }
};

int main()
{
    // ------------------------------------------------------------------
    // 1. Basic: apply a free function to a tuple
    // ------------------------------------------------------------------
    auto args = std::make_tuple(10, 20, 30);
    int sum = std::apply(add, args);

    std::cout << "=== Free Function ===" << std::endl;
    std::cout << "  add(10, 20, 30) = " << sum << std::endl;

    // ------------------------------------------------------------------
    // 2. Mixed types in the tuple
    // ------------------------------------------------------------------
    auto person = std::make_tuple(std::string("Alice"), 30, 1.72);
    std::string desc = std::apply(format_person, person);

    std::cout << "\n=== Mixed Types ===" << std::endl;
    std::cout << "  " << desc << std::endl;

    // ------------------------------------------------------------------
    // 3. Using a lambda
    // ------------------------------------------------------------------
    auto product = std::apply(
        [](int a, int b) { return a * b; },
        std::make_tuple(7, 8)
    );
    std::cout << "\n=== Lambda ===" << std::endl;
    std::cout << "  7 * 8 = " << product << std::endl;

    // ------------------------------------------------------------------
    // 4. Using a function object
    // ------------------------------------------------------------------
    Multiplier m{3};
    int result = std::apply(m, std::make_tuple(4, 5));
    std::cout << "\n=== Function Object ===" << std::endl;
    std::cout << "  3 * (4 + 5) = " << result << std::endl;

    // ------------------------------------------------------------------
    // 5. Applying std::make_pair via a tuple
    // ------------------------------------------------------------------
    auto pair_args = std::make_tuple(42, std::string("hello"));
    auto p = std::apply([](auto a, auto b) { return std::make_pair(a, b); },
                        pair_args);
    std::cout << "\n=== make_pair ===" << std::endl;
    std::cout << "  pair = {" << p.first << ", " << p.second << "}" << std::endl;

    return 0;
}

/*
Expected output:

=== Free Function ===
  add(10, 20, 30) = 60

=== Mixed Types ===
  Alice (age 30, 1.72m)

=== Lambda ===
  7 * 8 = 56

=== Function Object ===
  3 * (4 + 5) = 27

=== make_pair ===
  pair = {42, hello}
*/
Run command
g++ -std=c++17 -Wall -Wextra -o example apply.cpp