如何使用派生Ctor中模板基类的typedef?

时间:2018-10-09 15:41:27

标签: c++ templates inheritance

如果我有两个模板的基类和派生类:

template <typename T>
class Base {
public:
    typedef T (*func)();
    Base(func f):m_f(f){};
    T invoke(){ return m_f();};
private:
    func m_f;
};

template <typename D>
class Derived : public Base<D> {
public:
    Derived(Base<D>::func f) : Base<D>(f) { };
    D foo() {
        return Base<D>::invoke();
    }
};

派生类需要将函数指针传递给 Ctor 中的基址。阅读Inheritance and templates in C++ - why are methods invisible?后,我了解到Ctor中的typedef应该以以下方式调用:

Derived(Base<D>::func f) : Base<D>(f) {};

但是,当我尝试编译时:

int returnZero(){
    return 0;
}

Derived<int> d(returnZero);
std::cout << d.foo() << std::endl;

我得到:

  error: expected ')' before 'f'
  Derived(Base<D>::func f) : Base<D>(f) { };
                        ^
cpp_code.cpp: In function 'int main()':
cpp_code.cpp:59:27: error: no matching function for call to 'Derived<int>::Derived(int (&)())'
  Derived<int> d(returnZero);
                           ^
cpp_code.cpp:47:7: note: candidate: constexpr Derived<int>::Derived(const Derived<int>&)
 class Derived : public Base<D> {
       ^~~~~~~
cpp_code.cpp:47:7: note:   no known conversion for argument 1 from 'int()' to 'const Derived<int>&'
cpp_code.cpp:47:7: note: candidate: constexpr Derived<int>::Derived(Derived<int>&&)
cpp_code.cpp:47:7: note:   no known conversion for argument 1 from 'int()' to 'Derived<int>&&'

在Ctor中使用函数指针(func)的正确方法是什么?

1 个答案:

答案 0 :(得分:3)

通常,Clang会给出一条非常有用的错误消息,解释所有内容:

error: missing 'typename' prior to dependent type name 'Base<D>::func'
    Derived(Base<D>::func f) : Base<D>(f) { };
            ^~~~~~~~~~~~~
            typename 

如果从属名称是类型或模板,则应分别使用typenametemplate关键字来消除歧义。

这是必需的,因为在Derived定义中,编译器不知道将使用哪种类型来代替D,因此它不知道{{1 }}由于可能的专业化。这就是Base<D>内的任何标识符都依赖于类型Base<D>的的原因。

但是,编译器仍然需要能够解析它只能部分理解的代码,这就是为什么您需要通过告诉标识符D不只是{{1}的成员来提供帮助的原因},但func,因为它定义了可以使用此标识符的上下文。


在旁注:对于在只能使用类型(例如您的类型)的情况下,有一个proposal可以摆脱此烦人的规则。