如何让C++更倾向于匹配父类重载而不是模板?

4
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&?

我能否更改类以倾向于强制转换而非使用模板,从而不需要解决方法?


1
虽然 ChildParent 的一种,但是它仍然没有与 Parent& 直接匹配。因此,模板版本更适合匹配。 - Some programmer dude
1
一个解决方案是创建一个匹配的构造函数 Foo(Child&) {}; - user1810087
类似:https://stackoverflow.com/questions/26176516/choose-best-available-function-through-tag-inheritance - chris
2个回答

5
一种解决方案是通过 SFINAE 禁用模板构造函数:
template <
    typename T,
    std::enable_if_t<!std::is_base_of_v<Parent, T>> * = 0
>
Foo (const T &);

也许可以尝试使用const,因为const Parent parent; Foo{parent};没有匹配的构造函数(OP使用了Foo(Parent&)Foo(const T&)...)。 - Jarod42

0
编译器更喜欢选择模板构造函数,其中 T=child,因为重载决议认为限定符转换(将 const 添加到参数类型)比派生到基类转换更好。
所以最简单的方法就是声明一个以 child 为参数的构造函数:
class Foo
{
public:

    Foo (Parent &) {};

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

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

请注意,如果构造函数的参数是const lvalue或rvalue,那么就像你的示例代码一样,将选择模板构造函数。我想这是有意为之的。

1
Foo doesn't know about any subclasses of Parent - spraff

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接