Git Product home page Git Product logo

function_ref's Introduction

function_ref

A lightweight non-owning reference to a callable.

Clang + GCC: Linux Build Status MSVC: Windows Build Status

Use tl::function_ref instead of std::function whenever you don't need to own the callable. The most common case for this is function parameters which aren't stored anywhere:

void foo (function_ref<int(int)> func) {
    std::cout << "Result is " << func(21); //42
}

foo([](int i) { return i*2; });

Full documentation available here.


CC0

To the extent possible under law, Simon Brand has waived all copyright and related or neighboring rights to the function_ref library. This work is published from: United Kingdom.

function_ref's People

Contributors

mortenvp avatar rbrugo avatar tartanllama avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

function_ref's Issues

Warning with GCC

Hi @TartanLlama ,
We are also seeing a warning with g++:

In file included from ../../resolve_symlinks/function_ref-source/tests/call.cpp:2:
../../resolve_symlinks/function_ref-source/function_ref.hpp: In function ‘void ____C_A_T_C_H____T_E_S_T____0()’:
../../resolve_symlinks/function_ref-source/function_ref.hpp:93:29: warning: ‘<anonymous>’ may be used uninitialized in this function [-Wmaybe-uninitialized]
   return std::forward<Fn>(f)(std::forward<Args>(args)...);
          ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Seems to be triggered by this test:

    {
        int i = 0;
        tl::function_ref<void()> fr = [&i]{ i = 42; };
        fr();
        REQUIRE(i == 42);
    }

However, I'm not really sure how to fix it. The warning is triggered by g++ 8.2.0.

Can't store reference to a constant lambda

I'm unable to construct a function_ref from a const lambda:

#include "function_ref.hpp"                                                     
                                                                                
int main()                                                                      
{                                                                               
  const auto lam = [](int x) {};                                                
  tl::function_ref<void(int)> ref = lam;
  return 0;
} 

Is it possible with a work around? I tried adding a const post-fix in the template type but that doesn't seem to be supported either.

Wrong bit-width check in CMake tooling.

We would like to use function_ref in an ARM embedded (32bit) use-case. We use a CMake superbuild approach to prepare dependencies, where CMAKE_TOOLCHAIN_FILE is properly passed to the sub-build, so the library should be built in 32bit mode. However, when trying to include the dependent library, CMake refuses to select the just-build library, claiming that it is 64bit and thus does not match our architecture. a) The library should really be built for a 32bit environment, somehow it thinks it is being built for a 64bit environment. b) As the library is header-only, the build environment should not matter, and therefore there should not be any bit-width check in the installed tl-function-ref-config-version.cmake.

Default construction

Hi @TartanLlama
Thanks for this nice implementation - we've been wanting to use this in our code base for a while, and yesterday we gave it a try. However, we quickly ran into a problem: The function_ref object is not default constructional.

We use the function_ref objects as delegates, so often they are public members of the objects and we then later wire them together (like the includeos guys does here: https://youtu.be/QMb4RRFrY-o?t=1251).

What do you think about enabling default construction and having bool operator to check if initialized? I could make a pull-request if needed.

Move-assignment selects the wrong assignment operator

The greedy assignment operator is missing a constraint against assigning from the same type.

using FR = tl::function_ref<void(void)>;
static_assert(std::is_trivially_assignable<FR, FR&>::value, "");       // fails
static_assert(std::is_trivially_assignable<FR, const FR&>::value, ""); // OK
static_assert(std::is_trivially_assignable<FR, FR&&>::value, "");      // fails

The constraint is in P0792r5.

Visual C++ compiler behaviour

In all VC++ up to x64 msvc v19.20 with /std:c++latest, this compiles:

#include <iostream>
#include <vector>
#include <functional>

using T = tl::function_ref<int(const std::vector<int>)>;

void foo (const T& func) {
    std::cout << "Result is " << func({12}); //42
}

int main ()
{

int z = 12;
auto f = [&](const std::vector<int> i) { return i[0]*z; };
foo((T&) (f));

}

But not this:

#include <iostream>
#include <vector>
#include <functional>

using T = tl::function_ref<int(const std::vector<int>)>;

void foo (const T& func) {
    std::cout << "Result is " << func({12}); //42
}

int main ()
{

int z = 12;
auto f = [&](const std::vector<int> i) { return i[0]*z; };
foo(f);
}

Also works if one replaces vector with, say, int.

#include <iostream>
#include <vector>
#include <functional>

using T = tl::function_ref<int(int)>;

void foo (const T& func) {
    std::cout << "Result is " << func({12}); //42
}

int main ()
{

int z = 12;
auto f = [&](int i) { return i*z; };
foo(f);

}

Cannot use with non-copyable, non-movable return types in function signatures

In C++17 and later the new mandatory ellision of copy/move operations allow the following function:

NonCopyNonMoveType f() {
  return NonCopyNonMoveType();
}

even if NonCopyNonMoveType has neither an accessible copy constructor nor an accessible move constructor.

Given that definition of f, also the following is valid

NonCopyNonMoveType g() {
  return f();
}

However, the expression function_ref<NonCopyNonMoveType()>(f) will not compile.

The usual constructor is disabled because the requirement std::is_convertible_v<std::invoke_result_t<decltype(f)>,NonCopyNonMoveType> is not met.
That is the case because convertibility tests the possibility to construct a new function_ref return value from an rvalue of an existing return value of the supplied callable (in this case, it would be a move). However, under the new move ellision rules, no such move will actually happen. Therefore, in this case, the requirement rejects a callable that would be perfectly valid.

Should `Apple()` be convertible to `tl::function_ref<Fruit()>`?

https://godbolt.org/z/2r5aEI

struct Fruit {};
struct Apple : Fruit {};

Apple *getApple() { return nullptr; }

static_assert(std::is_invocable_r_v<Fruit*, decltype(getApple)>);

tl::function_ref<Fruit*()> bar()
{
    return getApple;  // ERROR: no such conversion
}

std::function permits implicit conversion from Apple*() to std::function<Fruit*()>, and from Apple() to std::function<Fruit()>, and I think these makes sense to support. (Similarly, from long() to std::function<int()>; I'm somehow less thrilled by that one, philosophically speaking.)

I believe the wording of @SuperV1234's P0792 supports such conversions, and intentionally so.

However, ulterior motive alert — watch out! — you might have to pick and defend a behavior for

Apple *getApple();
Apple *getRottenApple();
int main() {
    tl::function_ref<Apple*()> a = getApple;
    tl::function_ref<Apple*()> b = a;
    tl::function_ref<Fruit*()> c = a;
    a = getRottenApple;
    Fruit *rb = b();  // does this result in a call to getApple, or getRottenApple? why?
    Fruit *rc = c();  // does this result in a call to getApple, or getRottenApple? why?
}

function_ref should be trivially copyable

// https://godbolt.org/z/HnagzZ
#include <https://raw.githubusercontent.com/tartanllama/function_ref/master/function_ref.hpp>

static_assert(std::is_trivially_copyable_v<tl::function_ref<void()>>); // FAILS

I see no reason function_ref shouldn't be trivially copyable.

ABI breakage warning — but better to break now than break later! :) Also, @SuperV1234 informs me that the Standard-proposed version of function_ref will be trivially copyable in the next revision (because other people have had the same comment).

Cannot construct function_ref from function taking std::function as argument

Here is a simple reproducer that is giving me a compiler error on the latest clang:

using FuncGood = tl::function_ref<void(int, int)>;
FuncGood good = []( int, int ){}; // ok

using FuncBad = tl::function_ref<void(int, std::function<void()>)>;
FuncBad bad = []( int, std::function<void()> ){}; // compile error

In particular, the error message says that the desired constructor is not viable because the condition detail::is_invocable_r is not holding true, so I'm thinking there might be an issue with your implementation of is_invocable_r?

Relevant part of error message (I believe):

function_ref/function_ref.hpp:144:15: note: candidate constructor not viable: no known conversion from '(lambda at main.cpp:121:19)' to 'const function_ref<void (int, std::__1::function<void ()>)> &' for 1st argument function_ref/function_ref.hpp:153:32: note: candidate template ignored: requirement 'detail::is_invocable_r_impl<std::__1::integral_constant<bool, true>, void, (lambda at main.cpp:121:19) &&, int, std::__1::function<void ()> >::value' was not satisfied [with F = (lambda at main.cpp:121:19)]

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.