Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::function and lambda not respecting reference requirement

using viref_func = std::function<void(int& intref)>;
viref_func f1 = [](int foo) { ++foo; };
viref_func f2 = [](auto foo) { ++foo; };
viref_func f3 = [](int& foo) { ++foo; };
viref_func f4 = [](auto& foo) { ++foo; };

int test(0);
f1(test);
f2(test);
f3(test);
f4(test);

I half and half understand why f1 and f2 are valid (and analogous) code (but not "working as I want it to").

How can I make f1 fail compilation, requiring an int reference?

I don't care much if f2 fail or compiles, but if it compiles, the auto variable should be an int reference and not an int. It becoming an auto int ref would be the preferred way out.

f3 and f4 work as intended.

Addendum: references in std::function are used in my library code in a number of places. I want to make it easy on consumers of said library to catch dumb mistakes. I don't mind adding complexity in the library. I want to avoid making it hard on consumers of the library. A user having "auto" on a parameter rather than "auto&" (or proper_type&) caused a lot of problems at the user, and for me helping to track down the bug.

like image 811
oreubens Avatar asked Feb 05 '26 01:02

oreubens


1 Answers

You can wrap int to be uncopyable, but that requires changes to both the call site and the functions:

#include <functional>

template <typename T>
struct uncopyable
{
    T value;
    uncopyable(T value) : value(value) {}
    uncopyable(const uncopyable &) = delete;
    uncopyable(uncopyable &&) = delete;
    uncopyable& operator=(const uncopyable &) = delete;
    uncopyable& operator=(uncopyable &&) = delete;
};

int main()
{
    using viref_func = std::function<void(uncopyable<int>& intref)>;
    // viref_func f1 = [](int foo) { ++foo; }; // error as desired
    // viref_func f2 = [](auto foo) { ++foo; }; // also an error
    viref_func f3 = [](uncopyable<int>& foo) { ++foo.value; };
    viref_func f4 = [](auto& foo) { ++foo.value; };
    
    uncopyable<int> test(0);
    f3(test);
    f4(test);
}

See it on coliru

like image 172
Caleth Avatar answered Feb 08 '26 05:02

Caleth