有条件地添加到过载集是否合法

时间:2018-02-23 06:12:49

标签: c++ language-lawyer

考虑我们有接受某种基本类型的函数:

void print(const base&);

然后,我们在另一个标头中定义了一个继承自base的结构,称之为derived。最后在第三个标题中,我们有print的重载,它接受derived。总的来说,我们有这个:

// header 1
struct base {};
void print(const base&);

// header 2
#include "header 1"
struct derived:base{};

// header 3
struct derived;
void print(const derived&);

重要的是要注意print函数是在不同的TU中定义的。现在比较这两个TU:

// source 1
#include "header 2"

void foo() {
    derived d;
    print(d);
}

// source 2
#include "header 2"
#include "header 3"

void bar() {
    derived d;
    print(d);
}

print的调用看起来相同,但第一个源文件调用print(const base&),而第二个调用print(const derived&)。这种行为是否合法并且由标准强制执行?还是我在某个时候闯入UB?

如果print是模板函数,那么我们使用非模板方法重载print(忽略可以在非模板上选择模板方法,因为它可能更匹配,假设我们正确地重载它),合法性会被改变吗?

问题的部分原因源于想知道什么是合法和合理的定制来源,什么不是。标准库倾向于对类模板进行部分/显式特化。

1 个答案:

答案 0 :(得分:1)

这是合法的,但很脆弱。

如果您的foo在标题中作为内联函数,则会出现问题,因为您可能会破坏ODR(一个定义规则)。

然后

foo会根据之前的内容致电void print(const base&);void print(const derived&);

foo可能会被重写为:

void foo() {
    derived d;
    print(static_cast<Base&>(d));
}

明确选择哪个重载。

  

如果打印是模板函数,那么如果我们重载了打印

template <typename T> void print(const T&);

过载时,没有问题。

通过专精化,foobar将使用print<derived>,但使用不同的定义。