Std :: forward and copy constructor

I recently started using C ++. And I have a question about std :: forward with lvalue reference and rvalue reference. In my understanding, Func (mc) in the following code is supposed to call Func (T & t) due to the template parameter inference rule. And the copy constructor MyClass must be called inside the function with the message "copy constructor". However, I cannot get it when I run the program. I have verified that std :: forwad with rvalue reference and copy constructor works well on other strings. Please help me understand what is going on in the code. If I make a slight mistake or misunderstanding, I am sorry for taking the time. Thank you very much.

class MyClass {
public:
    MyClass() { printf("constructor.\n"); };
    MyClass(MyClass&) { printf("copy constructor.\n"); };
    MyClass(const MyClass&) { printf("const copy constructor.\n"); };
    MyClass(MyClass&&) { printf("move constructor.\n"); };
    int val = 3;
};

template <typename T>
void Func(T&& t) {
    T new_t_(std::forward<T>(t));
    new_t_.val *= 2;
};

main() {
    MyClass mc;
    Func(mc);  // lvalue <- Func(T&)
    Func(MyClass());  // rsvalue <- Func(T&&)
    printf("mc.val=%d\n", mc.val); // this is for check

    MyClass mc2(mc);  // this is for check of copy constructor
}

      

Displayed when the program is started,

constructor.
constructor.
move constructor.
mc.val=6
copy constructor.

      

I think it should have a "copy constructor" between the first and second "constructor" posts.

Thanks again.

+3


source to share


1 answer


Func(mc);

      

This call will output T

as MyClass&

. Pay attention to the link. This is because C ++ introduces perfect forwarding: a forwarding reference such as a function parameter T&&

Func

will be output as an lvalue reference if the corresponding function argument is an lvalue-expression; otherwise (for x and prvalues) it will not be inferred as a reference type.

The type inferred to T

will then be dumped using &&

a function parameter T&& t

to form the final type of the function parameter. In the case Func(mc)

, T == MyClass&

therefore the function parameter becomes MyClass& &&

compressed to MyClass&

.

Since T == MyClass&

, declaring a local variable new_t_

will declare a reference in this case. No new object will be created:

template <>
void Func<MyClass&>(MyClass& t) {
    MyClass& new_t_(std::forward<MyClass&>(t));
    new_t_.val *= 2;
}

      




Func(MyClass());

      

Here, the function argument is a prvalue expression MyClass()

. T

will output to MyClass

(no link). The created instance of the function template looks like this:

template <>
void Func<MyClass>(MyClass&& t) {
    MyClass new_t_(std::forward<MyClass>(t));
    new_t_.val *= 2;
}

      




If you want to copy / move a function argument to a local variable, the metafunction std::decay

can be used, or more specifically for the OP's problem, metafile std::remove_reference

. For example.

template <typename T>
void Func(T&& t) {
    using DT = typename std::decay<T>::type;
    DT new_t_(std::forward<T>(t));
    new_t_.val *= 2;
}

      

+5


source







All Articles