Как я могу сделать так, чтобы C ++ предпочитал соответствовать перегрузке родительского класса вместо шаблона?

class Parent {};

class Child : public Parent {};

class Foo
{
public:

Foo (Parent &) {};

template <typename T>
Foo (const T &);
};

int main ()
{
Child c;

Foo foo (c);
}

Это приводит к ошибке компоновщика, так как конструктор для foo выбирает template<typename T>Foo::Foo(const T &) вместо Foo::Foo(Parent&),

Если c имеет тип Parent вместо Child, это использует не шаблонный конструктор и ссылки без проблем.

Я могу обойти это с

Foo foo ((Parent&) c);

но я не хочу этого делать

Почему C ++ предпочитает использовать шаблон вместо неявного приведения c в Parent&?

Могу ли я изменить класс, предпочитая приведение типов к шаблону, чтобы обходной путь не был необходим?

3

Решение

Одним из решений является отключение конструктора шаблона через SFINAE:

template <
typename T,
std::enable_if_t<!std::is_base_of_v<Parent, T>> * = 0
>
Foo (const T &);
4

Другие решения

Компилятор предпочитает выбирать конструктор шаблона с T=child потому что разрешение перегрузки считает, что преобразование квалификации (добавление const к типу аргумента) лучше, чем производное в базовое преобразование.

Таким образом, самый простой способ — просто объявить конструктор, принимающий в качестве аргумента дочерний элемент:

class Foo
{
public:

Foo (Parent &) {};

Foo (Child & x):Foo(static_cast<Parent&>(x)) {};

template <typename T>
Foo (const T &);
};

Обратите внимание, что если аргументом конструктора является const lvalue или rvalue, то, как и в вашем примере кода, будет выбран конструктор шаблона. Я полагаю, что это намеренно.

0

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector