从模板类的实例化多重继承以及访问成员函数的内容

时间:2015-06-28 20:59:44

标签: c++ c++11 gcc clang

让我们来看看代码:

template <typename C>
class S {
public:
    void add (C c) { ++cnt; }
    size_t size () const { return cnt; }

private:
    size_t cnt {}; 
};

struct Foo1 {};
struct Foo2 {};
struct Foo3 {};

class Z : public S<Foo1>, public S<Foo2>, public S<Foo3> {
public:
    using S<Foo1>::add;
    using S<Foo2>::add;
    using S<Foo3>::add;

    using S<Foo1>::size;    // (1)
    using S<Foo2>::size;    // (2)
    using S<Foo3>::size;    // (3)
};

用法如下:

Z z;

z.add (Foo1 {});
z.add (Foo1 {});
z.add (Foo2 {});

cout << z.size () << endl;

这段代码用gcc-5.1(c ++ 11)编译好,但是这段代码不能在clang-3.5下编译(c ++ 11 - 抱歉,我没有更新版本的clang)。

Clang产生“错误:调用成员函数'size'是模棱两可的”这基本上(从我的角度来看)是正确的,但是gcc编译它并返回 2

好的,但如果我切换标有注释(1)和(2)的行的顺序,这里会更有趣,得到这样的结果:

using S<Foo2>::size;    // (2)
using S<Foo1>::size;    // (1)

代码仍然在gcc上编译,结果是: 1

你可以想象,如果你在这两个之前写第(3)行,你会得到 0

所以,从我看到的情况来看,gcc首先使用 S&lt; C&gt; :: size 的声明,忽略其余部分并使用此声明。

根据C ++标准,有人能告诉我哪个编译器正在做正确的工作吗?

报告https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66698

最佳, 阿图尔

1 个答案:

答案 0 :(得分:1)

这是一个gcc bug。 Clang和MSVC正确标记了歧义。

如果删除3个using语句,由于含糊不清,编译失败(应该如此):

prog.cpp:39:12: error: request for member 'size' is ambiguous
  cout << z.size () << endl; return 0;
            ^
prog.cpp:9:12: note: candidates are: size_t S<C>::size() const [with C = Foo3; size_t = unsigned int]
     size_t size () const { cout<<typeid(C).name()<<endl; return cnt; }
            ^
prog.cpp:9:12: note:                 size_t S<C>::size() const [with C = Foo2; size_t = unsigned int]
prog.cpp:9:12: note:                 size_t S<C>::size() const [with C = Foo1; size_t = unsigned int]

根据标准成员查找算法,尽管使用了decalartions,你应该得到相同的结果:

  

10.2 / 3:(...)在声明集中,using-declarations由他们指定的成员替换,并且类型声明(包括   注入类名称由他们指定的类型替换。

我无法找到与此错误完全匹配的内容。我建议你report it