std::function, it must have template argument? - c++

void hello(float i)
{
std::cout << "hello" << i << "\n";
}
int hollo(int a)
{
std::cout << "good" << a;
return 0;
}
int main(int, char**)
{
std::function hallo = hello;
hallo(3.0f);
hallo = hollo;
hallo(3);
while (true) {}
}
My code above works.
First, can I really use std::function without inserting a template argument, unlike internet examples?
Second, does this way of not using the template argument have any bad effects (decreasing performance, making the code hard to be managed and checked for type, or anything)?
Or, did it have any good effect (yea, I can make any function get into std::function only using =, it makes me happy)?

Can I use std::function without inserting template argument
Yes and no. std::function is a class template, and it must have template arguments, but (since C++17) those template arguments may be deduced from the function arguments of the constructor, in which case you don't have to specify the template arguments explicitly.
// deduced as std::function<void(float)>
std::function hallo = hello;
// no deduction; ill-formed
std::function broken;

The other answer says why this is allowed, but I want to mention that not specifying template arguments may cause readability issues sometimes. For example in the code you have shown, what do you expect the second call hallo(3); to do?
I assume you think that simply hollo is called with argument 3, but that is not the case. The type of hallo was deduced as std::function<void(float)> and that doesn't change in the assignment hallo = hollo;. So, actually, the argument 3 is first cast to float and then passed to hollo which implies that it is cast back to int again. These casts may change the value that ends up as the hollo argument. (Although very likely not for the value 3 specifically.)
Similarly you may expect hallo(3) to return an int, but it doesn't since the deduced function type for std::function has return type void.

Related

Is it valid to use std::function with incomplete types?

I wondered if it is valid to use std::function with incomplete type, e.g. in case of forward declaration. I wrote this small code:
#include <iostream>
#include <functional>
struct S;
std::function<S(void)> m;
struct S {
S() { std::cout << "ctor\n"; }
~S() { std::cout << "dtor\n"; }
void foo() { std::cout << "foo\n";}
};
S goo() {
return S{};
}
int main() {
m = goo;
m().foo();
}
Even though the S is incomplete in the point of declaring m, I could declare return type like a complete type(a non-pointer return type). This code complies and works correctly, but I'm not sure if this code is valid by standard. Because you cannot forward declare return type if it is not a pointer in a normal function(so I cannot forward declare S for goo()).
Any idea if this is a valid code by standard or not?
Any idea if this is a valid code by standard or not?
The program is well-formed because even though S is incomplete at the point of the definition std::function<S(void)> m;, the std::function doesn't place any requirement on S to be a complete type and instead requires that S be the name of a return type.
From std::function's documentation:
The function class template provides polymorphic wrappers that generalize the notion of a function pointer. Wrappers can store, copy, and call arbitrary callable objects, given a call signature, allowing functions to be first-class objects.
The above means that the template argument should be in the form of a call signature. From call signature's documentation:
A call signature is the name of a return type followed by a parenthesized comma-separated list of zero or more argument types.
(emphasis mine)
As we can see the above requires that S be the name of a return type. That is, it doesn't explicitly place any requirement on S being complete.
In other words, S in your given examples satisfies this condition so that it is valid.

Is it possible to handle non-primitive types in a variadic function?

I have 2 versions of the same variadic function, however one works the other doesn't. I suspect the reason is because one is using a primitive type where the other uses std::string.
void test1(int f_num, ...)
{
va_list file_names;
va_start(file_names, f_num);
for(int i=0; i<f_num; i++)
{
string name = string(va_arg(file_names, char*));
cout << name << endl;
}
va_end(file_names);
}
void test2(int f_num, ...)
{
va_list file_names;
va_start(file_names, f_num);
for(int i=0; i<f_num; i++)
{
string name = va_arg(file_names, string);
cout << name << endl;
}
va_end(file_names);
}
int main()
{
test1(3, "Hallo", "you", "people");
test2(3, "Hallo", "you", "people");
}
The above results in the following output:
Hallo
you
people
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Aborted (core dumped)
The first function thus works but the second doesn't. Am I correct to assume that it's because the variadic macro doesn't handle non-primitive types? Can you make it handle non-porimitive types?
va_arg decodes the va_list
You cannot use va_arg to convert the passed in variable argument parameter in a single go. The syntax of va_arg would be to decode the variable argument to match the type that was passed in. For example, if you pass in an int value, you must decode it as an int with va_arg. You cause undefined behavior if you try to decode it as anything else (like, as a double).
Since you passed in a string literal, the type should be const char *.
const char *arg = va_arg(file_names, const char *);
va_arg on non-trivial classes is implementation-defined
As MSalter's answer clearly explains, even if you really passed in a std::string to a function expecting variable arguments, it is not necessarily going to work because the semantics are implementation-defined.
When there is no parameter for a given argument, the argument is passed in such a way that the receiving function can obtain the value of the argument by invoking va_arg (18.10). … Passing a potentially-evaluated argument of class type (Clause 9) having a non- trivial copy constructor, a non-trivial move contructor, or a non-trivial destructor, with no corresponding parameter, is conditionally-supported with implementation-defined semantics. …
C++.11 §[expr.call] ¶7
Note: (18.10) defines va_arg, and (Clause 9) is §[class].
Just use a variadic template
You can use C++11's variadic template argument feature to achieve the effect you want in a type safe way. Assume you actually want to do a little more than print each argument, the usual pattern is to recursively traverse the parameter pack, unpacking one parameter at a time.
void test3 (int f_num, std::string file_name) {
std::cout << f_num << ':' << file_name << std::endl;
}
template <typename... T>
void test3 (int f_num, std::string file_name, T...rest) {
test3(f_num, file_name);
test3(f_num, rest...);
}
Thus, iteration is achieved by recursively calling the function, reducing the parameter pack by one parameter on the next recursive call.
The answer to the first part is that you're mostly correct. There are restrictions on the use of class types, in particular if they have a non-trivial copy constructor (which std::string has). It might work on some implementations and not on others. Formally, that's conditionally-supported with implementation-defined semantics.
The second part is a bit harder, but also a bit simpler. These varargs are old C, and not typesafe. C++ does have typesafe variadics, via templates:
template<typename... T>
void test1(T... args)
{
std::cout << ... << args << std::endl;
}
The problem is that you need to know how to unpack those args... - they're called parameter packs. There are a few different ways to unpack them; this particular form is called a fold expression.
If you call test2 as such, it should work:
test2(3, std::string("Hallo"), std::string("you"), std::string("people"));
What's happening here is that when you pass "Hallo" you're passing a char*, not an std::string, so when you try to retrieve the char* by giving it a type of std::string with va_arg, it fails since the object isn't an std::string.
Also, in some compilers, it seems that you can't pass types that aren't trivially destructable, when I tried this in cpp.sh it gave the error
In function 'void test2(int, ...)':
27:23: error: cannot receive objects of non-trivially-copyable type 'std::string {aka class std::basic_string<char>}' through '...';
In function 'int main()':
36:51: error: cannot pass objects of non-trivially-copyable type 'std::string {aka class std::basic_string<char>}' through '...'
Although it seems this isn't part of the standard as I couldn't find anywhere that required this, so I assume it's just a limitation of the compiler they're using. If anyone knows the details about this, I'll edit the answer with the correct information.
Like Henri Menke said, it seems the problem is that cpp.sh is using an old version that isn't c++11 compliant, so if you use a compiler that is at least c++11 compliant, you can use std::string within variadic arguments.
It appears this is an implementation detail, as miradulo said, so it will depend on your compiler, and not the standard version you're using.
And also, like Henri Menke mentioned, if you use
using std::string_literals;
And then put an 's' at the end of the normal string as such:
test2(3, "Hallo"s, "you"s, "people"s);
It transforms the char* to a std::string so you can use them like this to call test2, this is due to string literals.

Lambda as template function

I have a very strange problem. To keep things simple, lets say I want to have a function which takes 2 functions with the same declaration as arguments
template<typename Func>
void foo(Func a, Func b)
{
std::cout << "good";
}
To try things out I took putchar from cstdio, and created an identical function to match the putchar.
int myPutcharFunc(int)
{
return 0;
}
int main()
{
auto myPutcharLambda = [](int) -> int
{
return 0;
};
foo(putchar, myPutcharFunc); // okay
foo(putchar, myPutcharLambda); //deduced conflicting types for parameter 'Func' ('int (__attribute__((__cdecl__)) *)(int)' and 'main()::<lambda(int)>')
}
Now, the lambda does not want to compile (the key is I want to use lambda capture).
So lets add template specialization, because the programmer is wiser than the machine, right? :)
template<typename Func>
void foo(Func a, Func b)
{
std::cout << "good";
}
template<>
void foo(int(*)(int), int(*)(int))
{
std::cout << "good";
}
No luck, the same error - why?
But for some reason, when I comment out the template specialization:
//template<>
void foo(int(*)(int), int(*)(int))
{
std::cout << "good";
}
The code compiles. I obviously do not want to overload foo for EVERY set of function's arguments - thats what templates are for. Every step was tested both with msvc++ and g++. What am I doing wrong?
Two possibilities.
1: Just put + in front of the lambda:
foo(putchar, +myPutcharLambda);
That works because unary + expects an integer-like value, such as a pointer. Therefore, the lambda converts to a function pointer.
Ultimately a (non-capturing) lambda doesn't have the same type as a function pointer, even though it's willing to convert to a function pointer.
How is a compiler supposed to know which conversions are allowed to make two objects of the same type?
2: There is another option, making use of the fact that the ?: is willing to do some conversions, converting one type to another in some circumstances.
template<typename Func1, typename Func2>
void foo2(Func1 a, Func2 b)
{
using common_type = decltype(true?a:b); // or 'false', it doesn't matter
foo<common_type>(a,b);
}
Every lambda is a different type, so you'll need to have two different template parameters to get them
template<typename FuncA, typename FuncB>
void foo(FuncA a, FuncB b)
Types don't decay when deducing template types (SEE COMMENT FOR CORRECTION). So a lambda remains a lambda and doesn't decay to a function pointer. Same reason a string literal is deduced as a char[N] instead of a const char *.
With your second example using specialization, it doesn't want to use your specialization, since the lambda is not a function pointer. You can cast the Lambda to a function pointer and make it work: https://godbolt.org/g/ISgPci The trick you can do here is say +my_lambda because + is defined for pointers so it will force the non-capturing lambda to become a function pointer.
A lambda has its own type which can decay to a function pointer but not in the case of a template function match, it will for the real function as you found because of the implicit conversion.
In the case of matching to a template you need to disambiguate and explicitly instantiate foo with the type you want or convert the lambda to a function pointer.
foo<decltype(putchar)>(putchar, myPutcharLambda);
or
foo(putchar, +myPutcharLambda);

Confusion about what is actually happening with this decltype statement

So I was taking a look through http://en.cppreference.com/w/cpp/types/result_of and saw the syntax for doing result_of of a member function and I just don't understand what is going on with that decltype.
Why do the args come after the decltype? Wouldn't they be important in figuring out the type of the member function? In my mind I imagine that instead of decltype(&C::Func)(C, char, int&) it should be decltype(&C::Func(C, char, int&)) or something of the like, but I'm having a hard time wrapping my head around it. Can anyone please explain why it is this syntax?
std::result_of takes a template argument of the form F(A...). F should be a type that is callable, such as a function type or a class type with an overloaded operator(). A... should be a sequence of argument types.
Therefore, if you have some expression e and some argument types A... and you want to know what result type you will get if you call e with arguments of types A... then you would put F = decltype(e) in std::result_of<F(A...)>, that is, std::result_of<decltype(e)(A...)>.
I'm copying the relevant code from the example that you pointed to:
#include <type_traits>
struct C {
double Func(char, int&);
};
int main()
{
// result_of can be used with a pointer to member function as follows
std::result_of<decltype(&C::Func)(C, char, int&)>::type g = 3.14;
static_assert(std::is_same<decltype(g), double>::value, "");
}
decltype(&C::Func) is the declared type of method Func of C, which is a function taking a C reference (corresponding to this), a char and an int reference.
Let us call this type T.
Then, result_of<T(...)>::type will be the type of the result of applying a function of type T to the arguments whose types you specify in the parentheses.
Therefore, in this example, result_of<decltype(&C::Func)(C, char, int&)>::type will be double.
As you are aware, the type T1(T2,T3) means a function returning a value of T1 and taking arguments of type T2 and T3. As soon as you are working with values of that type, you are bound to that interpretation.
std::result_of does not deal with any values, just with a type of the form T1(T2,T3), so it technically has the freedom to interpret the types any way it likes. And it actually does! If std::result_of would be parametrized over the type of a function, and return the return type of that function, the result (i.e. nested type member) would just be T1, but it isn't. The standard writers chose to implement a different functionality: std::result_of takes the type T1 in it's type parameter not to be the return type of the function to be determined, but the complete type of some callable thing (e.g. a function pointer), and it will return the type returned by that callable thing when passed the arguments T1 and T2.
Example time!
#include <iostream>
#include <ostream>
#include <type_traits>
#include <typeinfo>
int main(void)
{
// define the type of a function
typedef int ftype(char, long);
// (A) doesn't compile: you can't call an int
std::cout << typeid(std::result_of<int(char,long)>).name() << '\n';
// (B) doesn't compile: A the return type of a function may not be a function
std::cout << typeid(std::result_of<ftype(char,long)>::type).name() << '\n';
// (C) does compile and print the typeid name of int. On g++ this is "i"
std::cout << typeid(std::result_of<ftype*(char,long)>::type).name() << '\n';
}
Case (A) fails, as int is not callable, although the template parameter itself is well-formed. Case (B) fails, as the template parameter is not well-formed. In T1(T2,T3), T1 must not be a function type, as types describing a function returning a function are forbidden. Case (C) has a valid template parameter, in which the return type of the "function" describes a callable type, so std::result_of is applicable.
With this context in mind, the answer to your question is likely obvious. The expression decltype(&C::Func)(C, char, int&) describes a function type returning decltype(&C::Func) and taking the parameter types C, char and int &. As already discussed, the return type has to be something callable, which is the case for decltype(&C::Func), as it is the pointer-to-member-function type double (C::*)(char, int&). According to the definition of the INVOKE operation (see the page about callable), this type is callable with a parameter list (C, char, int&), so the application std::result_of to decltype(&C::Func)(C, char, int&) is valid.
The alternative you suggest: std::result_of<decltype(&C::Func(C, char, int&))> is not valid, as &C::Func(C, char, int&) is not a valid expression. If you want to constrain the type (in case there are multiple overloads of Func), you can do that using a cast, though. decltype(static_cast<double (C::*)(int, char&)>(&C::Func)) is a valid expression, returning (no surprise there) the type double (C::*)(int, char&). But like in example (A), this is not a type you may apply std::result_of on.
The really interesting use-case for std::result_of is the case in which T1, the callable type, is a function object. By passing the type of a function object to std::result_of as T1, you are passing all function-call operators of that object at the same time and you can have std::result_of pick the right one using overload resolution. Passing "all the Func functions" like you pass "all the operator() functions" is not possible, because std::result_of is hardwired to look for operator() in case of objects, and you can't use the address-of operator to map operator() invocations to Func() invocations. You can write a template doing this mapping, though:
#include <iostream>
#include <ostream>
#include <type_traits>
#include <typeinfo>
class S {
public:
int Func(int);
double Func(float, float);
};
template <typename T>
class call_Func : public T {
public:
template<typename... args>
auto operator()(args... vals) -> decltype(this->Func(vals...)) { return this->Func(vals...); }
};
int main(void)
{
std::cout << typeid(std::result_of<call_Func<S>(int)>::type).name() << '\n';
}
The template call_Func redirects calling operator() on call_Func<S> to calling Func on the base class S (one should use std::forward, though), but note you can not write a "generic redirector" that gets the name of the function to redirect the function call operator to as template parameter, as you can neither pass overload set nor names as template parameters, but just types and constant values (for non-type parameters). Pointer-to-member-functions are one kind of constant value, but you already lost the overloading as soon as you form such a pointer.

Function overload using lambda function signature

Consider the following example
void foo(const std::function<int()>& f) {
std::cout << f() << std::endl;
}
void foo(const std::function<int(int x)>& f) {
std::cout << f(5) << std::endl;
}
int main() {
foo([](){return 3;});
foo([](int x){return x;});
}
This does not compile, because the call to foo is said to be ambiguous. As far as I understand this is due to the fact, that the lambda function is not a priori a std::function but has to be casted to it and that there is a std::function constructor that takes an arbitrary argument.
Maybe someone can explain to me why anyone would create an implicit constructor that takes an arbitrary argument. However my acutual question is whether there is a workaround, which allows to use the function signature of lambda functions to overload a the function foo. I have tried function pointers, but that didn't work because capturing lambda functions can't be cast to a normal function pointer.
Any help is most welcome.
Your compiler is correct according to C++11. In C++14, a rule is added that says that the constructor template shall not participate in overload resolution unless the type of the argument is actually callable with the std::function's argument types. Therefore, this code is supposed to compile in C++14, but not in C++11. Consider this to be an oversight in C++11.
For now, you can work around this by explicit conversion:
foo(std::function<int()>([](){return 3;}));
http://coliru.stacked-crooked.com/a/26bd4c7e9b88bbd0
An alternative to using std::function is to use templates. Templates avoid the memory allocation overhead associated with std::function. The template type deduction machinery will deduce the correct type of the lambda passed so the call site cast goes away. However you still have is disambiguate the overloads for the no-args vs args case.
You can do this using a trick with trailing return types that behave similar to enable_if.
template<typename Callable>
auto baz(Callable c)
-> decltype(c(5), void())
{
std::cout << c(5) << std::endl;
}
The above overload of baz will only be a valid overload candidate when the template parameter Callable can be called with an argument of 5.
You can put more advanced mechanisms on top of this to make it more general (ie. variadic pack expansion of args into callable) but I wanted to show the basic mechanism working.