std::function signature pointer vs pointer reference = no difference? - c++

Here is code example:
#include <string>
#include <functional>
struct Foo {};
typedef bool func_type(Foo *&, const std::string&);
typedef std::function<bool(Foo*&, const std::string&)> FunctionalType;
bool f(Foo *, const std::string&)
{
}
int main()
{
#if 1
func_type *func;
func = f;
#else
FunctionalType f2;
f2 = f;
#endif
}
As you see, I have declared function type with "reference to pointer" as the first argument Foo *&, and I expect that function with just "pointer" as the first argument Foo * cannot be assigned to a variable of this type.
The #if 1 region fails to compile (as I expect); however, the alternative did not emit any errors:
FunctionalType f2;
f2 = f;
Why does it compile without error (with at least gcc 5.2 and clang 3.7)?
How it can be fixed, so that std::function<Params> does not accept f for conversion?

std::function<R(Ts...)> is defined as a type whose objects can represent any function that can be called with arguments Ts... and whose return value is convertible to R.
Since your function f can be called with an lvalue of type T* as the first argument (which is the requirement that your Foo *& imposes), it is a valid function to be stored in your std::function.
There is no way to suppress this behavior that I know of.

std::function is a type-erasing container of invokable things.
It will store an instance of any C++ type that can be copied, destroyed and invoked with a "compatible" signature.
In this case, the signature is bool(Foo*&, const std::string&).
The core idea is that when Args... in the R(Args...) part of the std::function type is Foo*&, const std::string&, those arguments can be passed to a function expecting Foo* and const std::string&.
std::function works based on compatibility, not exact matching of signatures.
If you really, really need to ban things that do not take references:
template<class T>
struct reference_only {
T& t;
operator T&(){ return t; }
operator T()=delete;
reference_only(T& tin):t(tin){}
};
then use:
typedef std::function<void(reference_only<Foo*>)> FunctionalType;
which doesn't like being converted to a value-type, but accepts being converted to a reference type (of type Foo*& in this case).
Live example compiling, live example not compiling.

Related

std::bind with variadic template member function and universal references

Here i have small piece of code and it compiles and works just fine
(at least with my GCC 7.3.0 and Ubuntu 18.04):
#include <functional>
#include <string>
#include <iostream>
void func(int a, const std::string& b, const std::string& c)
{
std::cout << a << b << c << std::endl;
}
class Test
{
public:
template <typename ... ARGS>
bool func_to_bind(ARGS&& ... args) const {
func(args...);
return true;
}
template <typename ... ARGS>
void binding_func(ARGS&& ... args) const
{
auto func_obj = std::bind(&Test::func_to_bind<int&, ARGS&...>, this, 42, args...);
func_obj();
}
};
int main()
{
Test obj;
obj.binding_func(std::string("one"), std::string("two"));
}
The part that i don't understand is this line:
std::bind(&Test::func_to_bind<int&, ARGS&...>, this, 42, args...);
Why does compiler require to use references as template type parameters?
If i remove reference from int like this:
std::bind(&Test::func_to_bind<int, ARGS&...>, this, 42, args...);
It won't compile. Also if i change func_to_bind signature to this:
bool func_to_bind(ARGS& ... args) const
It will compile just fine even with missing reference.
Could anyone explain what's exactly going on here?
I also did some search and found this question:
How to combine std::bind(), variadic templates, and perfect forwarding?
But i don't completely understand the answer.
If you specify the template argument as int explicitly, then the parameter type of func_to_bind would become int&&, i.e. an rvalue-reference type. Note that the stored arguments are passed to the invokable object as lvalues by std::bind:
Otherwise, the ordinary stored argument arg is passed to the invokable object as lvalue argument:
The lvalue can't be bound to the rvalue-referece parameter then invocation fails.
If you specify the template argument as int& explicitly, then the parameter type of func_to_bind becomes int&, i.e. an lvalue-reference type; lvalue could be bound to lvalue-reference then it works fine.
And if you change the parameter type of func_to_bind to ARGS&, it'll be always an lvalue-reference, for the same reason above it'll work fine.

passing std::function as parameter with const void *

I have the following function declaration:
void get_data(struct myStruct* const value, const void * const data);
I have another function that I want to add a std::function as a parameter:
// I think the std::function definition is where my problem is
template<typename MyType>
void process(bool test, std::function<void(MyType* const, const void* const)>& callb) { ... }
However I can't quite figure out how to call it, or rather if my definition above is correct:
bool test1 = true;
process<myStruct>(test1, get_data);
Compiler Error:
error: prototype for ‘void process(bool, std::function<void(MyType* const, const void* const)>&)’ does not match any in class ‘MyClass’
void process(bool test,
error: candidate is: template<class MyType> void process(bool, std::function<void(MyType*, const void*)>&)
void process(bool test,
... goes on
Any ideas?
You basically just have to remove the reference from the function object:
void process(bool test, std::function<void(MyType* const, const void* const)> callb);
While a reference to a std::function object cannot be related to/converted from the underlying function pointer type, the non-referenced object can be implicitely converted to the function pointer type thanks to its constructor.
Edit: Passing std::function as const reference gives no performance benefit, but may actually include some penalty in some corner cases, see Should I pass an std::function by const-reference?
When passing get_value to callb, the compiler has to construct a temporary std::function object for callb. But callb is declared as a non-const reference, which cannot be bound to a temporary object. So make callb be a const reference instead, which can be bound to a temporary:
template<typename MyType>
void process(bool test, const std::function<void(MyType* const, const void* const)>& callb) { ... }
Live Demo

Function overloading with std::function argument: why is the const method never called?

#include <functional>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class A
{
public:
void doStuff(function<void (const string *)> func) const
{
cout << "Const method called" << endl;
for(const auto& i_string : m_vec)
func(i_string);
}
void doStuff(function<void (string *)> func)
{
cout << "Non-const method called" << endl;
doStuff([&func](const string *str)
{
auto mutableString = const_cast<string *>(str);
func(mutableString);
});
}
private:
vector<string *> m_vec;
};
int main()
{
auto a = A{};
a.doStuff([](string *str){
*str = "I modified this string";
});
}
In this example, the const method is never called. If the code looks weird, here's what I'm trying to do:
Instead of a getter method, I let clients iterate objects by passing a function. To enable both const and non-const access, I want to provide const and non-const overloads. Further, to avoid copy & paste, I want to implement the non-const method in terms of the const method: the const method in my code is actually more complicated than the one I use here.
Now, my questions is this: If you run this code, it will recursively call the non-const function until the stack overflows. I don't understand why the line doStuff([&func](const string *str) in the non-const method calls itself and not the const method.
The non-const method is declared as accepting function that can be called with string * argument. The provided function accepts const string *. string * is implicitely convertible to const string*. Therefore the function with const string * is acceptable argument for the non-const method and the non-const method is selected because this is non-const as well.
Use const_cast on this to use the const method:
const_cast<const A*>(this)->doStuff(…);
The const overload is only called when an instance of the A class is const. This is the case because of the const at the end of the declaration:
void doStuff(function<void (const string *)> func) const //This const at the end causes
//The member function to only be
//called when `a` is const
The const-qualifier at the end applies to the this object, not to the parameters. Removing the const will cause ambiguity, so use StenSoft's way to get it to work.
I don't think this is a correct overload:
void doStuff(function<void (const string *)> func) const
and
void doStuff(function<void (string *)> func)
Overloaded functions should have same prototype but different arguments. In your case your const method can only be called if your object is const. Here you have just 2 methods that can be called in different situations but these situations are not caused by overloading mechanism or any other argument-dependent feature.
Also, why not to let people use your object with default iterators? Implement begin() and end() methods in your object and let people do everything they want without your interface but std lib interface: they will be able to use ranged-for, some algorithms like find and find_if and else good things.
Metaprogramming boilerplate:
template<template<class...>class Z, class always_void, class...Ts>
struct can_apply_helper:std::false_type{};
template<template<class...>class Z, class...Ts>
struct can_apply_helper<Z,
decltype((void)(Z<Ts...>)),
Ts...>:std::true_type{};
template<template<class...>class Z, class...Ts>
using can_apply=can_apply_helper<Z,void,Ts...>;
Trait that detects if a type-expression would represent a valid call:
// result_of_t fails to be SFINAE in too many compilers:
template<class F, class...Ts>
using invoke_helper_t=decltype( std::declval<F>()(std::declval<Ts>()...) );
template<class Sig> struct can_invoke;
template<class F, class...Ts>
struct can_invoke<F(Ts...)>:
can_apply<invoke_helper_t, F, Ts...>
{};
Now, replacement doStuff in your class. The first one detects if you can call the function with a std::string const*:
template<class F, class=std::enable_if_t<
can_invoke< F&(std::string const*) >{}
>>
void doStuff(F&& func) const
{
cout << "Const method called" << endl;
for(const auto& i_string : m_vec)
func(i_string);
}
This one detects if you cannot call it with a std::string const* and that you can call it with a std::string*:
template<class F, class=std::enable_if_t<
!can_invoke< F&(std::string const*) >{} &&
can_invoke< F&(std::string*) >{}
>>
void doStuff(F&& func)
{
cout << "Non-const method called" << endl;
doStuff([&func](const string *str)
{
auto mutableString = const_cast<string *>(str);
func(mutableString);
});
}
this also removes the needless type erasure of std::function in your example, and routes any call that can go to the const method to the const method.
As an aside, storing a std::vector<std::string*> is almost always a bad idea.
Your reasoning may be that a lambda with the signature void(const string *) cannot be invoked with a string * and hence not converted to a function<void (string *)>. This is incorrect because a string * is implicitly convertible to a const string * and therefore it is perfectly legitimate to construct a function<void (string *)> object out of a function object expecting a const string *. It is only the obverse case that is not allowed. This means the compiler determines that both argument conversions are viable (with equal rank). This would make the two candidates ambiguous in overload resolution, but because the pointee of implicit this is non-const, the non-const overload is preferred (the rank of the implicit this is "exact match" for non-const vs. "conversion" for const).
The solution, as has previously been mentioned, is making sure the pointee of implicit this is const. This will eliminate the non-const overload from the candidate set and force an invocation of the intended overload.

How to filter const types and non const types using meta programing?

I have this code
#include <iostream>
size_t F()
{
return 0;
}
template <class Type, class... NextTypes>
size_t F(const Type& type, const NextTypes&... nextTypes)
{
if (!std::is_const<Type>::value)
return sizeof(type) + F(nextTypes...);
else
return F(nextTypes...);
}
int main()
{
int a = 0;
const int b = 0;
const size_t size = F(a,b);
std::cout << "size = " << size << std::endl;
return 0;
}
I'm trying to know in compilation time the total size of constant parameters and non const parameters. The current out put is 8, for some reason the compiler thinks b is not constant, I used typeid and decltype to print the types of a and b and indeed the output shows b is an int and not const int as I expected. What am I missing? Is it possible to separate a variadic set of arguments to const arguments and non const?
Consider this function template:
template<typename T>
void deduce(const T&);
If you let the compiler deduce a type for T from an argument expression, the deduced type will never be const: It will try to make the const T of the function parameter identical to the type of the argument expression used to call the function. For example:
struct cls {};
const cls c;
deduce(c) // deduces T == cls
By deducing T == cls, the compiler succeeds in making const T identical to the argument type const cls. There is no reason for the compiler to produce two different functions for const- and non-const argument types; the parameter type of the function template instantiation will be const-qualified in any case: you requested it by saying const T& instead of, say, T&.
You can deduce the const-ness of an argument by not cv-qualifying the function parameter:
template<typename T>
void deduce(T&);
However, this will fail to bind to non-const temporaries (rvalues). To support them as well, you can use universal references:
template<typename T>
void deduce(T&&);
This will deduce an lvalue-reference type for T if the argument is an lvalue, and no reference if the argument is an rvalue. The const-ness will be deduced correctly.
For example, if the argument has the type const A and is an lvalue, T will be deduced to const A&. The function parameter then is const A& &&, which is collapsed to const A& (an lvalue-reference). If the argument is an rvalue, T will be deduced to const A, and the function parameter becomes const A&& (an rvalue-reference).
Note that since T can be a reference in this case, you need to remove that before checking for const-ness: std::is_const< typename std::remove_reference<T>::type >::value.

Nested bind expressions

This is a followup question to my previous question.
#include <functional>
int foo(void) {return 2;}
class bar {
public:
int operator() (void) {return 3;};
int something(int a) {return a;};
};
template <class C> auto func(C&& c) -> decltype(c()) { return c(); }
template <class C> int doit(C&& c) { return c();}
template <class C> void func_wrapper(C&& c) { func( std::bind(doit<C>, std::forward<C>(c)) ); }
int main(int argc, char* argv[])
{
// call with a function pointer
func(foo);
func_wrapper(foo); // error
// call with a member function
bar b;
func(b);
func_wrapper(b);
// call with a bind expression
func(std::bind(&bar::something, b, 42));
func_wrapper(std::bind(&bar::something, b, 42)); // error
// call with a lambda expression
func( [](void)->int {return 42;} );
func_wrapper( [](void)->int {return 42;} );
return 0;
}
I'm getting a compile errors deep in the C++ headers:
functional:1137: error: invalid initialization of reference of type ‘int (&)()’ from expression of type ‘int (*)()’
functional:1137: error: conversion from ‘int’ to non-scalar type ‘std::_Bind<std::_Mem_fn<int (bar::*)(int)>(bar, int)>’ requested
func_wrapper(foo) is supposed to execute func(doit(foo)). In the real code it packages the function for a thread to execute. func would the function executed by the other thread, doit sits in between to check for unhandled exceptions and to clean up. But the additional bind in func_wrapper messes things up...
At the beginning, please let me introduce 2 key points:
a: When using nested std::bind, the inner std::bind is evaluated first, and the return value will be substituted in its place while the outer std::bind is evaluated. That means std::bind(f, std::bind(g, _1))(x) executes as same as f(g(x)) does. The inner std::bind is supposed to be wrapped by std::ref if the outer std::bind wants a functor rather than a return value.
b: The r-value reference cannot be correctly forwarded to the function by using std::bind. And the reason has already been illustrated in detail.
So, let's look at the question. The most importance function here might be func_wrapper which is intended to perform 3 purposes:
Perfect forwarding a functor to doit function template at first,
then using std::bind to make doit as a closure,
and letting func function template execute the functor returned by std::bind at last.
According to point b, purpose 1 cannot be fulfilled. So, let's forget perfect forwarding and doit function template has to accept a l-value reference parameter.
According to point a, purpose 2 will be performed by using std::ref.
As a result, the final version might be:
#include <functional>
int foo(void) {return 2;}
class bar {
public:
int operator() (void) {return 3;};
int something(int a) {return a;};
};
template <class C> auto func(C&& c) -> decltype(c()) { return c(); }
template <class C> int doit(C&/*&*/ c) // r-value reference can't be forwarded via std::bind
{
return c();
}
template <class C> void func_wrapper(C&& c)
{
func(std::bind(doit<C>,
/* std::forward<C>(c) */ // forget pefect forwarding while using std::bind
std::ref(c)) // try to pass the functor itsself instead of its return value
);
}
int main(int argc, char* argv[])
{
// call with a function pointer
func(foo);
func_wrapper(foo); // error disappears
// call with a member function
bar b;
func(b);
func_wrapper(b);
// call with a bind expression
func(std::bind(&bar::something, b, 42));
func_wrapper(std::bind(&bar::something, b, 42)); // error disappears
// call with a lambda expression
func( [](void)->int {return 42;} );
func_wrapper( [](void)->int {return 42;} );
return 0;
}
But, if you really want to achieve purpose 1 and 2, how? Try this:
#include <functional>
#include <iostream>
void foo()
{
}
struct bar {
void operator()() {}
void dosomething() {}
};
static bar b;
template <typename Executor>
void run(Executor&& e)
{
std::cout << "r-value reference forwarded\n";
e();
}
template <typename Executor>
void run(Executor& e)
{
std::cout << "l-value reference forwarded\n";
e();
}
template <typename Executor>
auto func(Executor&& e) -> decltype(e())
{
return e();
}
template <bool b>
struct dispatcher_traits {
enum { value = b };
};
template <typename Executor, bool is_lvalue_reference>
class dispatcher {
private:
static void dispatch(Executor& e, dispatcher_traits<true>)
{
run(e);
}
static void dispatch(Executor& e, dispatcher_traits<false>)
{
run(std::ref(e));
}
public:
static void forward(Executor& e)
{
dispatch(e, dispatcher_traits<is_lvalue_reference>());
}
};
template <typename Executor>
void func_wrapper(Executor&& e)
{
typedef dispatcher<Executor,
std::is_lvalue_reference<Executor>::value>
dispatcher_type;
func(std::bind(&dispatcher_type::forward, std::ref(e)));
}
int main()
{
func_wrapper(foo); // l-value
func_wrapper(b); // l-value
func_wrapper(bar()); // r-value
func_wrapper(std::bind(&bar::dosomething, &b)); // r-value
func_wrapper([](){}); // r-value
}
Let me explain some points:
To reduce lots of return statements, changing functor signature from int() to void().
The 2 run() function templates are used to check whether the original functor parameter is perfect forwarded or not.
dispatcher_traits is going to map bool constant to type.
You'd better name dispatcher::forward to differ from dispatcher::dispatch or you have to invoke std::bind template with dispatcher::forward's signature.
Looking at this the second time now, and I think I have a plausable explanation for the first error you are seeing.
In this case, it's more helpful to look at the complete error and the template instantiations that lead up to it. The error printed by my compiler (GCC 4.4), for example, ends with the following lines:
test.cpp:12: instantiated from ‘decltype (c()) func(C&&) [with C = std::_Bind<int (*(int (*)()))(int (&)())>]’
test.cpp:16: instantiated from ‘void func_wrapper(C&&) [with C = int (&)()]’
test.cpp:22: instantiated from here
/usr/include/c++/4.4/tr1_impl/functional:1137: error: invalid initialization of reference of type ‘int (&)()’ from expression of type ‘int (*)()’
Now looking at this bottom-up, the actual error message seems correct; the types the compiler has deduced are incompatible.
The first template instantiation, at func_wrapper, clearly shows what type the compiler has deduced from the actual parameter foo in func_wrapper(foo). I personally expected this to be a function pointer, but it is in fact a function reference.
The second template instantiation is hardly readable. But messing around with std::bind a bit, I learned that the format of the textual representation GCC prints for a bind functor is roughly:
std::_Bind<RETURN-TYPE (*(BOUND-VALUE-TYPES))(TARGET-PARAMETER-TYPES)>
So tearing it apart:
std::_Bind<int (*(int (*)()))(int (&)())>
// Return type: int
// Bound value types: int (*)()
// Target parameter types: int (&)()
This is where the incompatible types start. Apparently, even though c in func_wrapper is a function reference, it turns into a function pointer once passed to std::bind, resulting in the type incompatibility. For what it's worth, std::forward doesn't matter at all in this case.
My reasoning here is that std::bind only seems to care about values, and not references. In C/C++, there's no such thing as a function value; there's only references and pointers. So when the function reference is dereferenced, the compiler can only meaningfully give you a function pointer.
The only control you have over this is your template parameters. You will have to tell the compiler that you're dealing with a function pointer from the start to make this work. It's probably what you had in mind anyways. To do that, explicitly specify the type you want for the template parameter C:
func_wrapper<int (*)()>(foo);
Or the more brief solution, explicitly take the function's address:
func_wrapper(&foo); // with C = int (*)()
I'll get back to you if I ever figure out the second error. :)