Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Force compiler to choose copy constructor with const T& as a parameter

I'm writing a class where I have a templated constructor and copy constructor. Every time I want to call copy constructor with non const object, templated constructor gets chosen. How can I force compiler to choose copy constructor?

Here is the mcve:

#include <iostream>

struct foo
{
    foo()
    {
        std::cout << "def constructor is invoked\n";
    }

    foo(const foo& other)
    {
        std::cout << "copy constructor is invoked\n";
    }

    template <typename T>
    foo(T&& value)
    {
        std::cout << "templated constructor is invoked\n";
    }
};

int main()
{
    foo first;
    foo second(first);
}

Deleting a function is not what I want.

like image 648
Incomputable Avatar asked Sep 10 '16 08:09

Incomputable


People also ask

Is it necessary to have const for a reference in copy constructor?

When we create our own copy constructor, we pass an object by reference and we generally pass it as a const reference. One reason for passing const reference is, we should use const in C++ wherever possible so that objects are not accidentally modified.

What is const in copy constructor?

Copy Constructor in C++ ClassName (const ClassName &old_obj); Copy constructor is used to initialize the members of a newly created object by copying the members of an already existing object. Copy constructor takes a reference to an object of the same class as an argument.

Is there a default copy constructor in C++?

Default Copy Constructors: When a copy constructor is not defined, the C++ compiler automatically supplies with its self-generated constructor that copies the values of the object to the new object.

In what way a copy constructor is automatically invoked?

In C++, a Copy Constructor may be called for the following cases: 1) When an object of the class is returned by value. 2) When an object of the class is passed (to a function) by value as an argument. 3) When an object is constructed based on another object of the same class.


1 Answers

Add another constructor:

foo(foo& other) : foo( const_cast<const foo&>(other))  // for non-const lvalues
{
}

The first object in your example code is a non-const lvalue, therefore the compiler prefers foo(foo&) over foo(const &). The former is provided by the template (with T=foo&) and therefore is selected.

This solution involves providing a (non-template) constructor for foo(foo&) which then delegates construction to the copy constructor by casting it to a reference-to-const

Update, I've just realised that a foo rvalue will be taken by the template also. There are a number of options here, but I guess the simplest is to also add a delegate for foo(foo&&), similar to the one above

foo(foo&& other) : foo( const_cast<const foo&>(other))  // for rvalues
{
}
like image 127
Aaron McDaid Avatar answered Sep 30 '22 05:09

Aaron McDaid