C++0x 与 using 声明的混淆

发布于 2024-11-02 07:48:21 字数 725 浏览 5 评论 0原文

对于这种情况会发生什么:

struct A {
  void f();
};

struct B : virtual A {
  using A::f;
};

struct C : virtual A {
  using A::f;
};

struct D : B, C { 
  void g() {
    f();
  }
};

感兴趣的行是f()。显然,根据 FDIS 的 10.2 查找 f 成功并找到了 A::f。然而,超载决议会考虑哪些候选人呢?规范在 13.3.1p4 中写道:

对于通过 using 声明引入派生类的非转换函数,为了定义隐式对象参数的类型,该函数被视为派生类的成员。

这样做的目的是,对于单个类,如果这样的类既包含自己的成员函数,又包含将基类函数的名称纳入范围的 using 声明,则在重载解析期间,所有候选函数在其隐式对象中都具有相同的类类型范围。但这对于上面的例子意味着什么?候选人会是以下吗?

void F1(B&)
void F2(C&)
// call arguments: (lvalue D)

这似乎是错误的,因为根据10.2p7,我们在查找结果集中只有一个声明。我们该如何解释这个?

What should happen for this case:

struct A {
  void f();
};

struct B : virtual A {
  using A::f;
};

struct C : virtual A {
  using A::f;
};

struct D : B, C { 
  void g() {
    f();
  }
};

The line of interest is f(). Clearly the lookup of f according to 10.2 of the FDIS succeeds and finds A::f. However, what candidates will overload resolution consider? The spec says at 13.3.1p4:

For non-conversion functions introduced by a using-declaration into a derived class, the function is considered to be a member of the derived class for the purpose of defining the type of the implicit object parameter.

The intent of this is that for a single class, if such a class contains both own member functions and a using declaration bringing names of base class functions into scope, that during overload resolution all the function candidates have the same class type in their implicit object parameter. But what does this mean for the above example? Will the candidates be the following?

void F1(B&)
void F2(C&)
// call arguments: (lvalue D)

This appears to be wrong, because we only have one declaration in the lookup result set according to 10.2p7. How shall we interpret this??

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

心如狂蝶 2024-11-09 07:48:21

我认为,由于 10.2/7 产生的查找集仅产生一个声明,因此根本不存在函数重载。仅当 10.2/7 产生的查找集包含两个或多个声明时,13.3.1/4 才适用。

编辑:也许我没有我希望的那么清楚。即使 fA 中重载,我认为大多数相同的推理也适用。也许事情最好一步步来。 (请注意,在这种情况下,我使用与标准相同的 S(f, X) 表示法,但由于您的最派生类是 D,因此您的 S(f, D) 对应于它们的 S(f, C) 您的 S(f, B) 和 S(f, C) 对应于它的 S(f, B1) 和 S(f, B2)。

,并且 s(f, D) 是空的,因为我们没有直接包含在 D 中的 f 声明。基于此,我们得到 10.2/5。

在 10.2/6 中,我们首先将 s(f, B) 合并到 S(由于 s(f, D) 当前为空,因此我们遵循第一个要点下的第二个条件,并且 S(f, D) 成为 S(f, B) 的副本

。将 S(f, C) 转换为 S(f, D) 在这种情况下,S(f, C) 的每个子对象成员都是 S(f, D) 的子对象成员。 这满足第一个条件。要点,所以我们保持 S(f, D) 不变,合并完成,

此时,没有更多的基类 Bi 需要考虑,所以我们的 S(f, D) 。 = S(f, B)。最终重载集中完全没有来自 S(f, C) 的声明。

然后,如果 S(f, B) 包含两个或多个函数,我们继续进行 13.3.1,并解析重载集——但由于整个集来自 B,所以问题中提出的情况根本不存在。

I think that since the lookup set resulting from 10.2/7 results in only one declaration, there's no function overloading present at all. 13.3.1/4 would only apply when/if the lookup set resulting from 10.2/7 contained two or more declarations.

Edit: Perhaps I wasn't as clear as I'd hoped. Even if f is overloaded in A, I think most of the same reasoning applies. Perhaps it's best to take things step by step. (Note, that in this case, I'm using the same S(f, X) notation as the standard, but since your most derived class is D, your S(f, D) corresponds to their S(f, C), and your S(f, B) ans S(f, C) correspond to its S(f, B1) and S(f, B2).

First s(f, D) is empty, because we have no declaration of f directly contained in D. Based on that, we get to 10.2/5.

In 10.2/6, we start by merging s(f, B) into S(f, D). Since s(f, D) is currently empty, we follow the second condition under the first bullet point, and S(f, D) becomes a copy of S(f, B).

Then we have to merge S(f, C) into S(f, D). In this case, each of the subobject members of S(f, C) is a subobject member of S(f, D). This satisfies the first condition of the first bullet point, so we leave S(f, D) unchanged, and the merge is complete.

At that point, there are no more base classes Bi to consider, so our S(f, D) = S(f, B). None of the declarations from S(f, C) is present in the final overload set at all.

Then, if S(f, B) contained two or more functions, we proceed to 13.3.1, and resolve the overload set -- but since the entire set came via B, the situation posited in the question simply doesn't exist.

软糖 2024-11-09 07:48:21

只是猜测,完全不确定。 :)

[ Example:
struct A { int x; }; // S(x,A) = { { A::x }, { A } }
struct B { float x; }; // S(x,B) = { { B::x }, { B } }
struct C: public A, public B { }; // S(x,C) = { invalid, { A in C, B in C } }
struct D: public virtual C { }; // S(x,D) = S(x,C)
struct E: public virtual C { char x; }; // S(x,E) = { { E::x }, { E } }
struct F: public D, public E { }; // S(x,F) = S(x,E)
int main() {
F f;
f.x = 0; // OK, lookup finds E::x
}
S(x, F) is unambiguous because the A and B base subobjects of D are also base subobjects of E, so S(x,D)
is discarded in the first merge step. —end example ]

是 10.2p7 中的示例,其中 S(f,C) 表示查找集。最后提供的句子至关重要:由于 DE 具有相同的 C 基类,并且 E::x 隐藏了C中的x,使得F::x的最终使用变得明确。
现在,在您的示例中,没有任何内容隐藏 D 基类的 f,因此 D::f 的使用仍然不明确,并且我不明白 10.2p7 如何适用于你的情况。就像楼上说的,完全不确定。 ;)

Only speculation, totally not sure. :)

[ Example:
struct A { int x; }; // S(x,A) = { { A::x }, { A } }
struct B { float x; }; // S(x,B) = { { B::x }, { B } }
struct C: public A, public B { }; // S(x,C) = { invalid, { A in C, B in C } }
struct D: public virtual C { }; // S(x,D) = S(x,C)
struct E: public virtual C { char x; }; // S(x,E) = { { E::x }, { E } }
struct F: public D, public E { }; // S(x,F) = S(x,E)
int main() {
F f;
f.x = 0; // OK, lookup finds E::x
}
S(x, F) is unambiguous because the A and B base subobjects of D are also base subobjects of E, so S(x,D)
is discarded in the first merge step. —end example ]

Is the example from 10.2p7, where S(f,C) denotes the lookup set. The sentence provided at the end is essential: Since both D and E have the same C base class, and E::x hides the x from that C, making the final use of F::x unambigiuous.
Now, in your example, nothing hides the f of the base classes of D, so the use of D::f is still ambigiuous and I can't see how 10.2p7 applies to your case. Like said at the top, totally not sure. ;)

长梦不多时 2024-11-09 07:48:21

我不会直接解决这个问题,而是尝试论证假装每个派生类中都存在 f 函数是行不通的:

只有一个候选函数,并且它的类型

void A::(void)

为尽管您可以使用以下命令形成指向该函数的成员指针,

void (A::*F0)(void) = &A::f;
void (B::*F1)(void) = F0;
void (C::*F2)(void) = F0;

这是因为指向成员的指针包含计算函数参数所需的附加信息。指向成员的指针调用站点找到实际目标实例的 A 子对象,以提供 fthis 指针。函数内部没有逻辑从派生类型的 this 指针查找 A 的成员。因此,不能像您的问题所暗示的那样谈论 void F1(B* this)void F2(C* this)

如果函数被认为是派生类的成员,则为

void B::A::f(void);
void C::A::f(void);

但是由于 B::AC::A 是相同的基类,最终只有一个函数在候选列表中,尽管它在列表中出现了两次。然后,虚拟继承规定两个候选者都在同一个对象上调用相同的函数,没有歧义。

Instead of addressing the question directly, I'm going to try to argue that pretending there exist f functions in each of the derived classes doesn't work:

There's only one candidate function, and it has type

void A::(void)

Although you can form a pointer-to-member to that function with

void (A::*F0)(void) = &A::f;
void (B::*F1)(void) = F0;
void (C::*F2)(void) = F0;

This is because the pointer-to-member contains additional information necessary to calculate the parameter of the function. The pointer-to-member call site finds an A subobject of the actual target instance, to provide the this pointer of f. There's no logic inside the function to find A's members from a this pointer of derived type. So one can't talk about void F1(B* this) and void F2(C* this) as your question suggests.

If the functions are considered members of the derived class, it is as

void B::A::f(void);
void C::A::f(void);

But as B::A and C::A are the same base class, ultimately there is only one function in the candidate list, although it is in the list twice. Then virtual inheritance provides that both candidates are calling the same function on the same object, there is no ambiguity.

活雷疯 2024-11-09 07:48:21

我认为关键在于10.2p5,其中标准指的是检查每个“直接基类子对象”。

因为A 是虚拟继承的,所以它是D (10.1p4) 的“直接基类子对象”。

然后考虑 D 的三个子对象:ABC。到 10.2p6,BC 被消除(A 是它们的基础),并且只有 A::f > 是一名候选人。

I think the key is in 10.2p5, where the standard refers to checking each "direct base class subobject".

Because A is inherited virtually, it is a "direct base class subobject" of D (10.1p4).

Then three subobjects of D are considered: A, B, and C. By 10.2p6 B and C are eliminated (A is a base of these), and only A::f is a candidate.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文