What is the usage of std::forward in parameter passing? - c++

See the piece of code below(notice that s is a array with char instead of string):
#include <string>
#include <iostream>
#include <utility>
void func(std::string & s, char a) {
std::cout << "here1" << std::endl;
// ...
}
void func(std::string && s, char a) {
std::cout << "here2" << std::endl;
// ...
}
template <class T>
void foo(T && s) {
std::cout << "foo2" << std::endl;
func(s, ':');
//func(std::forward<T>(s), ':');
}
int main(int agrc, char *argv[])
{
//std::string s("a:b:c:d");
char s[8] = "abcdefg";
foo(std::move(s));
std::string s2("abcd")
foo(s2);
return 0;
}
If I replace func(s, ':') using std::forward, it makes no difference, the foo function will do the prefect forwarding without std::forward in this case.
Is there mis-understanding of 'prefect forwarding' with std::forward in C++11?

It makes a difference. In your case func(s, ':') will only ever call the overload of func that takes reference to a std::string.
The issue is that named variables and parameters are lvalues themselves and this is also the reason why std::forward exists in the first place.
In your example it has the appearance that the right overload is chosen for the first call to foo even if you don't use std::forward. This is just because you actually call foo with a char[] argument which is used to implicitly construct a temporary of std::string.

Lets consider first case foo(std::move(s)). Inside of foo, s will be bind to rvalue. But since it has a name (s) it's not an rvalue anymore. So when you pass s to func it will be like passing lvalue to it - it will trigger here1 version. But if you will pass s via std::forward it will be rvalue once again.
In second case s is lvalue reference when foo is entered, so it doesn't change anything whether you pass it directly or via std::forward. You would need to use std::move to get rvalue out of s again.

Related

How can I make it work,when passed "rvalue"?

code as follows:
#include <iostream>
#include<functional>
class TestCase {
public:
template<typename ...Args>
void myfun(Args&& ...args) {
sayhello(std::forward<Args>(args)...);
}
private:
void sayhello(const std::string& v, const std::string& v2) {
std::cout <<" ---1---- " << v << "," << v2 << std::endl;
}
};
template<typename ...Args>
void test(Args&& ...args) {
TestCase a;
auto f = std::bind(&TestCase::myfun<Args...>, &a,std::forward<Args>(args)...);
f();
}
int main() {
std::string a = "1";
std::string b = "2";
test(a,b); //ok
test("1","2"); //error
return 0;
}
why std::forward not work? I tried pass value by lvalue and it work,but pass value by rvalue not work.I confused with TestCase::myfun<Args...> ,should it be TestCase::myfun<Args&&...> or something else?
The problem is similar to that in std::bind and rvalue reference.
std::bind will always copy the arguments and store them. When you use "1", "2", TestCase::myfun<Args...> is instantiated with Args = const char &[2], while the arguments are stored as const char * (due to the copy), so the error occurs since the parameter const char &[2] does not match arguments of const char *.
When you use std::string("1"), std::string("2"), TestCase::myfun<Args...> is instantiated with Args = std::string (so the parameter type is std::string &&). The error still occurs since the parameter std::string && does not match the stored arguments, which are lvalues.
As you have found, using lambda is a proper solution.

returning a rvalue parameter as a rvalue reference

On this thread (Should I return an rvalue reference parameter by rvalue reference?), it is written that The parameter cannot be a temporary (which is just what rvalue references represent).
If I understand this sentence well, this code should not be correct
#include <string>
#include <iostream>
std::string &&f(std::string &&a) {
return std::move(a);
}
int main() {
std::string a = f("lol");
std::cout << a << std::endl;
return 0;
}
However, when we look to std::get, it seems that it returns rvalue reference for temporary tuple, and I actually think that there is no issue with using std::get with temporary tuple.
So, I think I misunderstand the sentence above, and the prior code is correct. However, this one is not correct :
#include <string>
#include <iostream>
std::string &&f(std::string &&a) {
return std::move(a);
}
int main() {
std::string &&a = f("lol");
std::cout << a << std::endl;
return 0;
}
It would be correct if the function returns a value and not rvalue reference. Am I correct?

Universal reference template type always evaluate to lvalue

My code:
#include <string>
#include <utility>
#include <iostream>
void store(std::string & val)
{
std::cout << "lvalue " << val << '\n';
}
void store(std::string && val)
{
std::cout << "rvalue " << val << '\n';
}
template<typename T> void print(T && val)
{
std::cout << std::boolalpha << std::is_lvalue_reference<T>::value << " ";
store(std::forward<T>(val));
}
int main()
{
std::string val("something");
print(val);
print("something else");
}
my output:
true lvalue something
true rvalue something else
I've read on Universal referencing and understand why T is a lvalue when the input is a lvalue but I don't understand how is T a lvalue when the input is a rvalue, how does that collapse to the right paramter?
I don't understand how is T a lvalue when the input is a rvalue, how does that collapse to the right paramter?
No, the input is not an rvalue.
String literals are lvalues, and that's what you pass as a parameter to the function. That's why "true" is printed.
Now, recall that string literals cannot be modified (String Literals).
So, "something else" is of lenght 14 + 1 (for the null terminator), thus a const char[15].
Now, since string literals cannot be modified, the reference will be deduced as:
const char(&)[15];
The prototype of your method is:
store(std::string && val)
which creates a temporary std::string from const char.
The problem is not the forwarding reference. It's that you aren't passing a std::string rvalue to the function.
You are passing a string literal that is 15 character long, its type is const char[15]. And string literals are non-modifiable lvalues, so the reference is deduced as const char (&)[15].
The reason you see your rvalue overload printing is because, well, you can construct a temporary std::string out of a character array.

Implicit argument conversion ambiguity in non-member functions overloads with std::function?

Editted - please skip to the edit, which has the real problem
I frequently run into situations in my string helper library of stand-alone functions, where I provide overloads of a function with versions that take a char and versions that take a std::string.
The problem is, the overload then becomes ambiguous when passed a string literal (const char*).
Example:
void myFunc(const std::string &subStr);
void myFunc(char character);
These two functions are implemented differently, one optimized for strings and one for a single char.
Howsoever, trying to call myFunc("literal") results in ambiguity, despite me always wanting it to call the std::string version.
This forces me to provide void myFunc(const char *str) versions of my overloads, which only are stubs like:
void myFunc(const char *str)
{
myFunc(std::string(str));
}
Is there some way to make these stub functions unnecessary? I'd like to just be able to make void myFunc(char c) 'explicit', but you can't make non-constructor non-member functions explicit. Which would solve the problem instantly. =(...
(As an aside, why can't you make standalone functions explicit?)
Edit:
You know what they say about programmers coding too late into the night! (If you remember the joke, tell me, because I was too sleepy when I originally heard it and I've since forgotten it)
The real problem
I'm using MinGW v4.7.2, and the problem was alot different then my post originally assumed.
The problem is, I have several overloads. Yes, this example works fine:
void myFunc(const std::string &subStr);
void myFunc(char character);
But if you add an std::function overload, it breaks down:
void myFunc(const std::string &subStr);
//Not actually part of the problem; I was confused by part of the error message highlighting this function.
//void myFunc(char character);
void myFunc(std::function<bool(char)); //<-- The real problem
My string library has std::string, char, and std::function overloads (and occasionally a few more overloads for simplifying functions with alot of optional parameters).
When I have std::function as an overload, I get this error message:
error: call of overloaded ‘myFunc(const char [15])’ is ambiguous
candidates are:
void myFunc(char) <near match>
no known conversion for argument 1 from ‘const char [15]’ to ‘char’
void myFunc(std::function<bool(char)>)
void myFunc(const string&)
The myFunc(char) was how I initially got confused last night. Removing that overload from the code, I get the error message:
error: call of overloaded ‘myFunc(const char [15])’ is ambiguous
candidates are:
void myFunc(std::function<bool(char)>)
void myFunc(const string&)
Here's a self-contained compilable example.
How can I make a string literal choose the std::string over the std::function?
It's probably ambiguous because std::function's constructor is templated and is designed to take a function pointer, among other things.
Since my string library, specifically, uses only std::function<bool(char)> and std::function<bool(const std::string&)>, already typedef'd, I could inherit those into a class with an explicit constructor.
Is there other suggestions or options available?
Can you update your compiler? Your example compiles as expected in g++4.8 and above.
This is actually is a current defect report in the C++ standard. See 2132. std::function ambiguity. It is currently in review status, but most likely will be accepted. This will make sure that non-Callable types like your example never participate in overload resolution:
These constructors shall not participate in overload resolution unless
f is Callable
Currently g++4.8 and above implements this.
You did not provide self-contained repro so it's hard to say what's wrong.
But here are a couple of guesses:
You have a bug in compiler (unlikely)
You don't call character overload properly. You should call it like that: myFunc('c').
You provided incorrect calling code or incorrect method signature(s).
I guess following code snippet should explain what should be happening and how to declare and call methods properly. Note myOtherFunc trick with capturing literal. It can be done better w/o template function, with smart wrapper around string, but I'll leave that out.
You can also try it on your compiler and see if it works, then we'll know if you have compiler problem.
Live code: http://codepad.org/gzB7xWs2
#include <string>
#include <iostream>
using namespace std;
void myFunc(char c) {
cout << "myFunc called with char" << endl;
}
void myFunc(const string& s) {
cout << "myFunc called with string" << endl;
}
void myOtherFunc(char c) {
cout << "myOtherFunc called with char" << endl;
}
void myOtherFunc(const string& s) {
cout << "myOtherFunc called with string" << endl;
}
template <size_t StingSizeWithNullTerminator>
void myOtherFunc(const char (&buf)[StingSizeWithNullTerminator]){
cout << "myOtherFunc called with literal of size " << (StingSizeWithNullTerminator - 1) << endl;
}
int main() {
myFunc("string");
myFunc('c');
myFunc(string("std string"));
myOtherFunc("string");
myOtherFunc('c');
myOtherFunc(string("string"));
return 0;
}
Output:
myFunc called with string
myFunc called with char
myFunc called with string
myOtherFunc called with literal of size 6
myOtherFunc called with char
myOtherFunc called with string
Update
Now, with the example, it's clear what the problem is.
The problem is that there is no method with exact signature that accepts char[15]. And compiler needs to perform conversion.
The problem is that it can either convert to std::string or to std::function (because std::function has template constructor which accepts any type, including char[15]). Therefore it can't choose which conversion to use and gives up.
Therefore there's no clean solution for that as far as I know of, but here are some no-so-clean:
Use explicit conversion to std::string when calling methods
Ask yourself (and maybe tell us), what's the reason for having myFunc which accepts both strings and functions. Maybe there's a problem with design and you can avoid having functions with same names.
If you only need to accept bool(&)(char) function, you can use custom wrapper instead (see example below)
Example for 3rd option (http://ideone.com/o0NqUf):
#include <iostream>
#include <functional> //Required for std::function.
struct Callback
{
Callback(bool (&func)(char)): m_func(func)
{}
bool operator()(char c) { return m_func(c); }
bool (&m_func)(char);
};
void myFunc(Callback seperatorFunc)
{
std::cout << "Callback overload" << std::endl;
}
void myFunc(const std::string &separator)
{
std::cout << "std::string overload" << std::endl;
}
bool testCallback(char)
{
return true;
}
int main()
{
myFunc("String literal");
myFunc(std::string("std::string"));
myFunc(testCallback);
return 0;
}
Output:
std::string overload
std::string overload
Callback overload
You should be able to SFINAE yourself very easily out of this one:
template <typename F>
auto myFunc(F f) -> decltype(!f('0'), std::function<bool(char)>(f), void()) {
std::cout << "std::function<bool(char)> overload" << std::endl;
}
Or, using a C++03 compiler (possibly using tr2/type_traits or Boost Type Traits if your compiler doesn't yet have them):
template <typename F>
void myFunc(F f, typename std::enable_if<std::is_constructible<
std::function<bool(char)>, F>::value>::type* = nullptr)
{
std::cout << "std::function<bool(char)> overload" << std::endl;
}
Proof it works:http://ideone.com/Q87JsV
#include <iostream>
#include <type_traits>
#include <functional>
#if 1
template <typename F>
auto myFunc(F f) -> decltype(!f('0'), std::function<bool(char)>(f), void()) {
std::cout << "std::function<bool(char)> overload" << std::endl;
}
#else
template <typename F>
void myFunc(F f, typename std::enable_if<std::is_constructible<
std::function<bool(char)>, F>::value>::type* = nullptr)
{
std::cout << "std::function<bool(char)> overload" << std::endl;
}
#endif
void myFunc(const std::string &seperator) {
std::cout << "std::string overload" << std::endl;
}
bool testCallback(char) {
return true;
}
int main()
{
myFunc("String literal");
myFunc(std::string("std::string"));
myFunc(testCallback);
}
Output:
std::string overload
std::string overload
std::function<bool(char)> overload

A common type cast for lambda's and functions to reference later

Why is it the second example does not work? Is there a way I could get the second example to work while still type casting the lambda or function into a medium to reference later?
// Types I'm using
typedef void (*ANY_FUNC)(...);
typedef void (*VOID_FUNC)();
This works
void call_void( VOID_FUNC func) {
((ANY_FUNC)func)();
};
// ...
call_void([]() { /* do something */ });
This doesn't
template <typename fn>
void call_any( fn func ) {
((ANY_FUNC)func)();
};
// ...
call_any([]() { /* do something */ });
Please ignore the fact that you would never need to use the second example how it is now. It's only for demonstration (relative code).
Both examples work with function pointers instead of lambdas.
As long as you are declaring a template you can just use the incoming function object directly. Also, you should declare your function argument as a reference not as by value:
template <typename fn>
void call_any(fn&& func) {
func();
};
And if you want to call a function with arguments you can do:
template <typename fn, typename... Args>
void call_any_many(fn&& func, Args&&... args) {
func(std::forward<Args>(args)...);
};
Usage example:
int main ()
{
call_void([]() { std::cout << "Hello, void World!" << std::endl; });
call_any([]() { std::cout << "Hello, any World!" << std::endl; });
call_any_many([](int x) { std::cout << "Hello, any many World-" << x << "!" << std::endl; }, 1234);
return 0;
}
But if your intention is to store some function pointers and not to call them directly, I suggest using std::function from <functional> header. You can see some information and example from here: http://en.cppreference.com/w/cpp/utility/functional/function
For example:
#include <iostream>
#include <functional>
int main ()
{
std::function<void()> anyf = []() { std::cout << "Hello, any World!" << std::endl; };
std::function<void(int)> intf = [](int x) { std::cout << "Hello, any many World-" << x << "!" << std::endl; };
anyf();
intf(1234);
return 0;
}
I don't think any of them really works, except perhaps by chance on some compilers.
The difference with a lambda is that it is convertible to a function pointer, but it isn't one. The templated version will notice this difference, and fn is not deduced as VOID_FUNC.
Lambdas are implicitly convertible to function pointers (but only if they don't capture anything), so just change call_any's parameter to a function pointer:
void call_any(ANY_FUNC func)
{
(*func)();
}
You would need to call it with a lambda of the appropriate type:
call_any([](...) { /* ... */ });
But variable-length argument lists (aka varargs) are bad because they are as non-type-safe as you can get. Same with function pointers: they are non-object-oriented. You should think of an alternative mechanism, perhaps involving variadic templates and polymorphism (virtual methods)
The first is converting a lambda to a function pointer with corresponding argument and return types, then casting that to a vararg function, whereas the second is attempting to convert a lambda directly to a vararg function (i.e., a function without corresponding argument types).
The two conversions in the first example are allowed*, but the single conversion in the second is not.
* Note that the cast notation you use to convert between function pointer types ends up working like reinterpret_cast which states: "A function pointer can be explicitly converted to a function pointer of a different type. The effect of calling a function through a pointer to a function type (8.3.5) that is not the same as the type used in the definition of the function is undefined." And therefore the first example code has undefined behavior.