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

北城余情 提交于 2020-02-27 23:17:30

问题


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.


回答1:


The problem is that first is mutable, so a reference to it is a foo& which binds to the universal reference T&& more readily than const foo&.

Presumably, you intended that T was any non-foo class?

In which case a little bit of enable_if chicanery expresses intent to the compiler without having to write a load of spurious overloads.

#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, std::enable_if_t<not std::is_base_of<foo, std::decay_t<T>>::value>* = nullptr>
    foo(T&& value)
    {
        std::cout << "templated constructor is invoked\n";
    }

};

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

expected output:

def constructor is invoked
copy constructor is invoked
templated constructor is invoked



回答2:


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
{
}


来源:https://stackoverflow.com/questions/39424341/force-compiler-to-choose-copy-constructor-with-const-t-as-a-parameter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!