function2 icon indicating copy to clipboard operation
function2 copied to clipboard

function_view cannot bind to const lambda

Open nitronoid opened this issue 6 years ago • 5 comments

@Naios


Expected Behavior

The const-ness of the callable should be propagated to the erased function pointer

Actual Behavior

In file included from main.cpp:1:0:
function2.hpp: In instantiation of ‘static void* fu2::abi_400::detail::type_erasure::address_taker<T, <template-parameter-1-2> >::take(O&&) [with O = const main()::<lambda()>&; T = main()::<lambda()>; <template-parameter-1-2> = void]’:
function2.hpp:1184:51:   required from ‘constexpr fu2::abi_400::detail::type_erasure::erasure<false, Config, fu2::abi_400::detail::property<IsThrowing, HasStrongExceptGuarantee, Args ...> >::erasure(T&&) [with T = const main()::<lambda()>&; Config = fu2::abi_400::detail::config<false, true, fu2::capacity_default>; bool IsThrowing = true; bool HasStrongExceptGuarantee = false; Args = {int()}]’
function2.hpp:1376:72:   required from ‘constexpr fu2::abi_400::detail::function<Config, fu2::abi_400::detail::property<IsThrowing, HasStrongExceptGuarantee, Args ...> >::function(T&&) [with T = const main()::<lambda()>&; fu2::abi_400::detail::function<Config, fu2::abi_400::detail::property<IsThrowing, HasStrongExceptGuarantee, Args ...> >::enable_if_not_convertible_to_this<T>* <anonymous> = 0; fu2::abi_400::detail::function<Config, fu2::abi_400::detail::property<IsThrowing, HasStrongExceptGuarantee, Args ...> >::enable_if_can_accept_all_t<T>* <anonymous> = 0; fu2::abi_400::detail::function<Config, fu2::abi_400::detail::property<IsThrowing, HasStrongExceptGuarantee, Args ...> >::assert_wrong_copy_assign_t<T>* <anonymous> = 0; fu2::abi_400::detail::function<Config, fu2::abi_400::detail::property<IsThrowing, HasStrongExceptGuarantee, Args ...> >::assert_no_strong_except_guarantee_t<T>* <anonymous> = 0; Config = fu2::abi_400::detail::config<false, true, fu2::capacity_default>; bool IsThrowing = true; bool HasStrongExceptGuarantee = false; Args = {int()}]’
main.cpp:9:42:   required from here
function2.hpp:249:26: error: invalid conversion from ‘const void*’ to ‘void*’ [-fpermissive]
     return std::addressof(obj);

Steps to Reproduce

#include "function2.hpp"
int main()
{
  const auto callable = []{ 
      return 5;
  };  

  fu2::function_view<int()> view(callable);
}
g++ -std=c++14 main.cpp

Your Environment

>$ g++ --version
g++ (GCC) 7.3.1 20180303 (Red Hat 7.3.1-5)
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

nitronoid avatar Jan 24 '19 15:01 nitronoid

From my point of view this is the intended behaviour here because there is no way to access a method qualified as const from a non const context without ignoring the qualifier.

If you want to create a function_view to a const callable object use fu2::function_view<int() const> view(callable);

Implementing it in a way you are proposing would heavily violate the const guarantees provided by the library, because then the constness of an erased object is not propageted to the callable erasure anymore.

Naios avatar Jan 24 '19 16:01 Naios

Hi, thanks for the fast reply. Firstly, the method you suggest fails with the same error:

#include "function2.hpp"

int main()
{
  const auto callable = []{ 
      return 5;
  };  

  fu2::function_view<int() const> view(callable);
}

Secondly I disagree with your final remark. If it is guaranteed that casting any pointer to void* and back will yield the same pointer, and you are not modifying the stored pointer, then I don't see where the violation occurs? This code appears valid to me:

#include "function2.hpp"
#include <iostream>

using func_t = int (*const)();

int main()
{
  const auto callable = [](){
      return 5;
  };

  func_t fptr = callable;
  void* ptr = (void*)(fptr);
  auto cptr = (func_t)(ptr);
  std::cout<<cptr()<<'\n';
}

I'm am however happy to be told otherwise, thanks

nitronoid avatar Jan 24 '19 16:01 nitronoid

See folly/function for a basic explanation. It's about halfway down and I quote the beginning:

Other than copyability, there is one more significant difference between std::function and folly::Function, and it concerns const-correctness. std::function does not enforce const-correctness: it allows you to store mutable callables (i.e. callables that may change their inner state when executed, such as a mutable lambda) and call them in a const context (i.e. when you only have access to a const reference to the std::function object). For example ...

ladnir avatar Jan 24 '19 18:01 ladnir

That does make sense, so could you explain why my const example doesn't compile?

nitronoid avatar Jan 24 '19 19:01 nitronoid

Seems like there is a bug in the implementation, I'll provide a fix for that soon.

Naios avatar Jan 24 '19 20:01 Naios

Any update on this? I was testing and noticed

  const auto callable = [] { 
      return 5;
  };  
  fu2::function_view<int() const> view(callable);

still doesn't work

wak-google avatar Dec 03 '22 03:12 wak-google

@wak-google Sadly I did not look into this yet. Mainly I thought this issue has not a super high priority.

Naios avatar Dec 05 '22 08:12 Naios

Any update? :smiley:

wak-google avatar Jul 01 '23 01:07 wak-google

Fixed in fa0b7082494c53fd3e393af758088aec54ce6304

Naios avatar Jul 13 '23 21:07 Naios