I have a class in which I overloaded method. Depending on lifetime of the object given method will be called.
How can I call fun implementation for temporary objects? I thought that std::move() casts its argument to an rvalue. Could you tell me why the code below does not work as intended?
template <typename T>
void fun(T&& arg) {
arg.callamethod();
}
class TestCall {
private:
public:
void callamethod() && {
std::cout << "R VALUE REF" << std::endl;
}
void callamethod() const & {
std::cout << "CONST L VALUE REF" << std::endl;
}
void callamethod() & {
std::cout << "L VALUE REF" << std::endl;
}
};
int main() {
TestCall arg = TestCall();
const TestCall arg2 = TestCall();
fun(arg);
fun(arg2);
fun(std::move(arg)); // calls callamethod() &
fun(std::move(arg2)); // calls callamethod() const &
}
Change your function fun to the following code and you will see that rvalue qualifier on your method callamethod works as expected.
template <typename T>
void fun(T&& arg) {
std::forward<T>(arg).callamethod();
}
Note that the last call:
fun(std::move(arg2));
resolves to the const lvalue option of callamethod as you do not have a const rvalue qualifier option, if you add one it will go to it.
Related
My code is as follows:
#include <iostream>
using namespace std;
class A{
public:
void sendByRvalue(string&& str){
cout << str << endl;
}
};
class B{
private:
A a;
void send(string&& str){
a.sendByRvalue(str);
}
public:
void run(const string& str){
send("run " + str + "\n");
}
};
int main(void){
string str("hello world");
B b;
b.run(str);
return 0;
}
When I compile the code shown above, I got some compile errors:
It seems that the str in B::send function has been changed to lvalue. Then I change the implement of B::send, like:
class B{
private:
A a;
void send(string&& str){
cout << boolalpha << is_rvalue_reference<decltype(str)>::value << endl;
a.sendByRvalue(std::move(str));
}
public:
void run(const string& str){
send("run " + str + "\n");
}
};
Everything goes well, but the output of this program made me confuse more. The output is as follows:
Why the parameter str is a rvalue reference but I cannot pass it to the function A::sendByRvalue directly without std::move ?
str is a named rvalue reference, which is treated in the language as an lvalue. rvalues are only xvalues or prvalues, and str is neither.
A note from the standard, on the xvalue rules:
In general, the effect of this rule is that named rvalue references are treated as lvalues and unnamed rvalue references to objects are treated as xvalues; rvalue references to functions are treated as lvalues whether named or not.
struct A {
int m;
};
A&& operator+(A, A);
A&& f();
A a;
A&& ar = static_cast<A&&>(a);
The expressions f(), f().m, static_cast<A&&>(a), and a + a are xvalues. The expression ar is an lvalue.
I'll make a simpler example to explain
void bar(std::string&& name) {
std::cout << "Bar: " << name << std::endl;
}
void foo(std::string&& name) {
bar(name);
}
int main() {
foo("C++");
}
This is more or less the same as the example you have provided. Inside foo(), name is an lvalue. The temporary string C++, which is an rvalue is passed into name. name is an lvalue. So the above code is basically translated to.
void bar(std::string&& name) {
std::cout << "Bar: " << name << std::endl;
}
int main()
{
std::string foo{ "C++" };
bar(foo);
}
Now it seems obvious where the problem is.
I wrote this simple program to help you understand better
void foo(const std::string& name) {
std::cout << "Passed as lvalue ref: " << name << std::endl;
}
void foo(std::string&& name) {
std::cout << "Passed as rvalue ref: " << name << std::endl;
}
We'll use this function to call
void bar(std::string&& name) {
foo(name);
}
int main() {
bar("C++");
}
Passed as lvalue ref: C++
This proves my point, now what if we use std::move()?
void bar(std::string&& name) {
foo(std::move(name));
}
int main() {
bar("C++");
}
Passed as an rvalue ref: C++
If you want a simple way to check whether an expression is an lvalue or rvalue, you can try the below snippet
template <typename T>
constexpr bool is_lvalue(T&) {
return true;
}
template <typename T>
constexpr bool is_lvalue(T&&) {
return false;
}
source
I tried to build a very simple version of std::function. Below the code of a very first version. My question is about the lifetime of the temporary object from the lambda-expression, because I'm actually storing a reference to it. Or is the lifetime of the object prolonged?
It tried to use a copy of the function (T mf instead of const T& mf inside struct F), but that gives an error due to the decaying of the function to a pointer.
#include <iostream>
template<typename T>
struct F {
F(const T& f) : mf{f} {
std::cout << __PRETTY_FUNCTION__ << '\n';
}
void test() {
std::cout << __PRETTY_FUNCTION__ << '\n';
mf();
}
const T& mf;
};
template<typename T>
struct F<T*> {
F(T f) : mf{f} {
std::cout << __PRETTY_FUNCTION__ << '\n';
}
void test() {
std::cout << __PRETTY_FUNCTION__ << '\n';
mf();
}
T* mf;
};
void g() {
std::cout << __PRETTY_FUNCTION__ << '\n';
}
int main() {
F<void(void)> f1(g);
f1.test();
auto g1 = g;
F f2(g1);
f2.test();
F f3([](){ // lifetime?
std::cout << __PRETTY_FUNCTION__ << '\n';
});
f3.test();
auto l1 = [](){
std::cout << __PRETTY_FUNCTION__ << '\n';
};
F f4(l1);
f4.test();
}
You do have lifetime problems here: lifetime extension thanks to const only applies for local const references.
You need to make sure that the referenced function lives at least as long as the wrapper, or you need to copy/move the function into the wrapper.
but that gives an error due to the decaying of the function to a pointer
You can use std::decay_t<T> to ensure that you're copying/moving objects (e.g. closures) into the wrapper.
#include <iostream>
struct object1 {
object1(int v) : type(1), value(v) {}
int type;
int value;
};
struct object2 {
object2(int v) : type(2), value(v) {}
int type;
int value;
};
template <typename HeaderType>
void foo(HeaderType * hdr) {
std::cout << "foo called with type " << hdr->type << " and value " << hdr->value << std::endl;
}
// this function doesn't work
template <typename HandlerType>
void dispatch(int type, int val, HandlerType handler) {
if (type == 1) {
object1 h(val);
handler(&h);
} else {
object2 h(val);
handler(&h);
}
}
int main() {
int type = 1;
int val = 1;
// this part works
if (type == 1) {
object1 h(val);
foo(&h);
} else {
object2 h(val);
foo(&h);
}
// trying to replicate the above behavior in a more abstract way,
// ideally via a function call of the following sort
//
// dispatch(type, val, ..foo..? );
}
The above program takes an input value, uses it to decide what type of object to create, then calls a function foo with a pointer to that object.
Question: Is it possible to create this sort of abstraction where the caller of dispatch doesn't know the exact types that foo will be called with but the dispatch function doesn't know the specific function that is going to be called?
With
template <typename HandlerType>
void dispatch(int type, int val, HandlerType handler) {
if (type == 1) {
object1 h1(val);
handler(&h1);
} else {
object2 h2(val);
handler(&h2);
}
}
All branches should be valid, so handler(&h1) and handler(&h2) should be valid calls.
For that, handler may be a generic lambda (since C++14) as suggested in comment:
dispatch(type, val, [](auto a) {return foo(a);} );
or you may create your own functor:
struct foo_caller
{
template <typename HeaderType>
void operator () (const HeaderType* hdr) const {
std::cout << "foo called with type " << hdr->type << " and value " << hdr->value << std::endl;
}
};
And then call it:
dispatch(type, val, foo_caller());
The following errors due to the const int specialization:
#include <iostream>
using std::cout;
using std::endl;
template <typename T> void g(T val)
{
cout << "unknown" << endl;
}
template <> void g(int && val)
{
cout << "int &&" << endl;
}
template <> void g(const int && val)
{
cout << "const int &&" << endl;
}
template <> void g(int & val)
{
cout << "int &" << endl;
}
template <> void g(const int & val)
{
cout << "const int &" << endl;
}
template <> void g(int val)
{
cout << "int" << endl;
}
template <> void g(const int val) //redefinition here
{
cout << "const int" << endl;
}
int main() {}
error: redefinition of 'g'
template <> void g(const int val)
^
Why are T& and T&& distinct from const T& and const T&& but T is not distinct from const T?
Because top-level const-ness of function parameters is an implementation detail of the function. For example, the following is valid:
// Prototype
void foo(int c);
// Implementation
void foo(int const c) { ... }
Since the argument is passed by value, the caller doesn't really care whether the function is going to modify its own private copy. Therefore, top-level const-ness is not part of the function signature.
Note that this only applies to top-level const-ness! int and int const are equivalent in a function prototype, as are int * and int * const. But int * and int const * are not.
When using arguments there are a few things to take into consideration, A: Not passing an arguement by reference is creating its own new variable, and B: Passing by reference is using the same variable as the argument with a different name
This is important because:
void doStuff (const int x)
{
//x is its own constant variable
}
Whereas
void doStuff (const int& x)
{
//because x is the same variable that was used when calling this function
//x can be modified outside of this function, but not inside the function
//due to the const modifier
}
The const modifier on the 2nd function allows you to do things like this:
int main ()
{
const int x = 10;
doStuff(x)
}
References are used to modify a variable in another function and to save memory on the stack, this saves memory because it uses a pointer rather than a newly created variable, so anything larger than an int will save memory by calling using a reference even if you arent modifying it in the function
Now if i am correct the && operator should not be used in an argument because this is a boolean operator and does not modify the argument type. It should only be used in conditions but wouldnt create a syntax error when compiling (compiler thinks its a reference of type [type] &) but that does nothing to the way the variable is used besides taking slightly longer for the computer to process
class Foo
{
friend class SquirrelVM;
public:
Foo() { cout << "Ctor" << endl; }
virtual ~Foo() { cout << "Dtor" << endl; }
Foo(const Foo & o) { cout << "const Ctor" << endl; }
template <typename _ty>
Foo(const _ty & val) { cout << "T const Ref" << endl; }
template <typename _ty>
Foo(_ty & val) { cout << "T Ref" << endl; }
template <typename _ty>
Foo(_ty * val) { cout << "T Ptr" << endl; }
};
Foo CreateFoo()
{
Foo ret;
return ret;
}
int main( int argc, char* argv[] )
{
Foo f = CreateFoo();
return 0;
}
Outputs are different between vs2005 and vs 2010.
Expected outputs are like this..
Ctor
const Ctor
Dtor
Dtor
Above outputs are derived if I build in vs2005.
But, vs2010's output is not same with vs2005's
Ctor
T Ref
Dtor
Dtor
Why template function's priority is higher than normal function in vs2010?
[edit]
If const is ommitted on copy constructor, than expected output(which is same with vs2005) comes out. Is there any side effect if form of copy constructor is not same with recomended form? Recomended form.. I mean... Foo(const Foo&); not Foo(Foo&);
Foo(_ty & val) with _ty being Foo is a better match because it will have parameter type Foo& matching a non-const Foo lvalue, while the other has a const that will make it a bit worse match.
There was some confusion during the made-up process of C++0x and before as to whether templates can be used to copy an object of a class to its own class type. The committee just recently figured they want to stop the confusion about it and allow such a thing. VS2010 seems to reflect that decision.