How can I make C++ prefer to match a parent class overload instead of a template?

4092 views c++
3

class Parent {};

class Child : public Parent {};

class Foo
{
public:

    Foo (Parent &) {};

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

int main ()
{
    Child c;

    Foo foo (c);
}

This produces a linker error since the constructor for foo chooses template<typename T>Foo::Foo(const T &) instead of Foo::Foo(Parent&).

If c has type Parent instead of Child, this uses the non-template constructor and links with no issues.

I can work around this with

Foo foo ((Parent&) c);

but I don't want to do that.

Why does C++ prefer to use a template instead of implicitly casting c to Parent&?

Can I change the class to prefer casting to templating, so the workaround is not needed?

answered question

While Child is-a Parent, there's still no direct match to Parent&. Therefore the templated version is a better match.

One solution is to create a matching constructor Foo (Child&) {};.

2 Answers

2

One solution is to disable the template constructor through SFINAE:

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

posted this
2

You can use std::is_base_of type trait:

#include <type_traits>

class Parent {};

class Child : public Parent {};

class Foo
{
public:

    Foo (Parent &) {};

    template
    <
        typename T
    ,   ::std::enable_if_t<not ::std::is_base_of_v<Parent, T>> * = nullptr
    >
    Foo (const T &);
};

int main ()
{
    Child c;
    Foo foo (c);
    return 0;
}

online compiler

posted this

Have an answer?

JD

Please login first before posting an answer.