C ++用模板和虚函数标记疯狂

时间:2015-02-09 17:24:33

标签: c++ templates g++ clang++

在重构一个相当大的代码库的过程中,我的编译器想出了一个误解我的好方法。这是我所说的最简单的例子:

#include <iostream>

class Foo {
public:
        virtual int get() = 0;
        template <typename T> int get(int i) { return 4 + i; }
};

class Bar : public Foo {
public:
        virtual int get() { return 3; }
};

int main(int argv, char **argc) {
        Bar b;
        std::cout << b.get<char>(7) << std::endl;
        return 0;
}

Clang 3.6,gcc 4.7,gcc 4.8和gcc 4.9都标记了&#34; b.get(7)&#34;作为&#34; b.get&#34;之间的比较运算符和&#34; char&#34;。

template-test.cpp: In function ‘int main(int, char**)’:
template-test.cpp:16:17: error: invalid use of non-static member function
  std::cout << b.get<char>(7) << std::endl;
                 ^
template-test.cpp:16:21: error: expected primary-expression before ‘char’
  std::cout << b.get<char>(7) << std::endl;
                     ^

(这是gcc 4.9,其他人说类似的东西)

这应该有用吗?

我找到的解决方法是声明模板化的&#34; get&#34;在基类和派生类中。

1 个答案:

答案 0 :(得分:9)

派生类中的名称get会在基类中隐藏名称get。因此,在执行名称查找时找不到函数模板get(),并且编译器只能以您看到的方式解释这些标记。

您可以在using课程中使用Bar声明来解决此问题:

class Bar : public Foo {
public:
    using Foo::get;
//  ^^^^^^^^^^^^^^^
    virtual int get() { return 3; }
};

这是live demo on Coliru

如果您无法修改Bar的定义,因为它不在您的控制之下,我猜您可以将调用限定为get()

std::cout << f.Foo::get<char>(7) << std::endl; // get() template is found now.

有关实时演示,请参阅here。另一种选择是通过指针或对Foo

的引用来执行调用
Bar b;
Foo& f = b;
std::cout << f.get<char>(7) << std::endl; // get() template is found now.

再次live example