CodeNebula
C++23stlexpert

std::invoke_r (C++23 Addition)

C++23 · Completing Modern · Compiler flag: -std=c++23

Explanation

Invokes a callable with a specified return type.

Real-World Scenario

Call a function with type-safe return in an event system.

Quick Snippet

snippet.cpp
#include <functional> auto result = std::invoke_r<int>(func, args...);

Full Example

invoke_r.cpp
// CodeNebula - C++23 Example: std::invoke_r
// Compile: g++ -std=c++23 -Wall -Wextra -o example invoke_r.cpp
// Note: Requires GCC 13+ / Clang 17+

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

// std::invoke_r<R>(f, args...) invokes a callable and converts the
// result to type R. Useful for explicit return type control, including
// invoking callables that return void when you need a specific type.

int add(int a, int b) { return a + b; }

struct Multiplier {
    double factor;
    double operator()(double x) const { return x * factor; }
};

struct Widget {
    int value;
    int get_value() const { return value; }
};

// A function returning int that we want to use as returning double
int compute() { return 42; }

// Void-returning function: invoke_r<void> discards any return value
int side_effect_func() {
    std::cout << "  (side effect executed)\n";
    return 999;  // Return value will be discarded by invoke_r<void>
}

int main() {
    std::cout << "=== std::invoke_r with explicit return type ===\n\n";

    // Basic: invoke free function, convert int result to double
    double result = std::invoke_r<double>(add, 3, 4);
    std::cout << "invoke_r<double>(add, 3, 4) = " << result << "\n";
    std::cout << "Type is double? "
              << std::is_same_v<decltype(result), double> << "\n\n";

    // Invoke function object
    Multiplier mul{2.5};
    double product = std::invoke_r<double>(mul, 4.0);
    std::cout << "invoke_r<double>(Multiplier{2.5}, 4.0) = " << product << "\n\n";

    // Invoke member function
    Widget w{100};
    long val = std::invoke_r<long>(&Widget::get_value, w);
    std::cout << "invoke_r<long>(&Widget::get_value, w) = " << val << "\n\n";

    // Invoke lambda with return type conversion
    auto lambda = [](int x) { return x * x; };
    double sq = std::invoke_r<double>(lambda, 7);
    std::cout << "invoke_r<double>(square_lambda, 7) = " << sq << "\n\n";

    // invoke_r<void> discards the return value
    std::cout << "invoke_r<void> discards return value:\n";
    std::invoke_r<void>(side_effect_func);
    std::cout << "  (return value was discarded)\n\n";

    // Convert int to bool
    auto is_positive = [](int x) { return x; };
    bool positive = std::invoke_r<bool>(is_positive, 5);
    std::cout << "invoke_r<bool>(is_positive, 5) = "
              << std::boolalpha << positive << "\n";

    return 0;
}

// Expected output:
// === std::invoke_r with explicit return type ===
//
// invoke_r<double>(add, 3, 4) = 7
// Type is double? 1
//
// invoke_r<double>(Multiplier{2.5}, 4.0) = 10
//
// invoke_r<long>(&Widget::get_value, w) = 100
//
// invoke_r<double>(square_lambda, 7) = 49
//
// invoke_r<void> discards return value:
//   (side effect executed)
//   (return value was discarded)
//
// invoke_r<bool>(is_positive, 5) = true
Run command
g++ -std=c++23 -Wall -Wextra -o example invoke_r.cpp