【问题标题】:C++ : Function call Compile-Time Error from a Template Class using Typename as BaseC++:使用 Typename 作为基础的模板类中的函数调用编译时错误
【发布时间】:2016-02-24 16:35:35
【问题描述】:

我不知道也无法找到概念名称来简单地形成我的问题(还有标题)。所以我发布了整个代码。下面是代码,有两个基类。还有一个使用类模板创建的派生类。派生类使用类型名 T 继承了两个基类。每个基类都具有称为 foo() 和 boo() 的唯一函数。

我的问题是:
1) 在这种情况下,是否可以在派生类中同时使用函数调用(在 callMethods() 中)?我遇到错误,不知道如何解决。
2) 或者如果现有的设计有问题,我需要更改类设计吗?
3)如果设计正确,这样设计类是一种好习惯吗?

错误信息:

error: 'boo' is not a member of 'mybase_1'
         T::boo();     
error: 'foo' is not a member of 'mybase_2'
         T::foo();      
                ^                ^

测试代码:

enum class myenum : int {one, two};

class mybase_1{
protected:
    void foo(){
        qDebug() << "foo called\n";
    }
};

class mybase_2{
protected:
    void boo(){
        qDebug() << "boo called\n";
    }
};

template <typename T>
class myderived : public T{
public:
    myderived(myenum _enm);
    void callMethods();
private:
    myenum enm;
};

template <typename T> myderived<T>::myderived(myenum _enm):enm{_enm}{
    qDebug() << "derived constructor\n";
}
template <typename T> void myderived<T>::callMethods(){
    switch(enm){
    case myenum::one:
        T::foo();
        break;
    case myenum::two:
        T::boo();
        break;
    }
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    myderived<mybase_1> tmp1(myenum::one);
    tmp1.callMethods();
    myderived<mybase_2> tmp2(myenum::two);
    tmp2.callMethods();

    return a.exec();
}

【问题讨论】:

  • callMethods() 部分看起来非常错误。你应该通过专业化和sfinae来解决这个问题。
  • @πάνταῥεῖ 指出callMethods 函数是问题所在。当您使用类型(例如,mybase_1)实例化 myderived 类并让它使用 callMethods 函数时,编译器必须编译它,显然 mybase_1 没有 boo 函数。你仍然需要编写有效的代码来满足编译器的要求。
  • 我曾经写过一篇博文来记住这项技术。 Conditional type selection using C++ template specializations
  • @jeet ...你能具体说明你要做什么吗?
  • @πάνταῥεῖ。感谢您分享概念名称。我会调查的。

标签: c++ templates inheritance


【解决方案1】:

1) 在这种情况下,是否可以在派生类中同时使用函数调用?

在您的实现中,只有派生类或基类实现了这两个功能。

我遇到了错误,不知道如何解决。

类型在编译时是已知的,因此最简单的解决方案是专门化模板:

template<>
void myderived<mybase_1>::callMethods(){
    foo();
}
template<>
void myderived<mybase_2>::callMethods(){
    boo();
}

如果你不需要枚举做其他事情,那么你可以把它和 switch 语句一起扔掉。

【讨论】:

  • 这是我想要的解决方案:)。 C++ 总是灵活的。感谢您的宝贵时间。
【解决方案2】:

1) 只是为了纠正你的错误——你的 switch case 是

switch(enm){
case myenum::one:
    T::foo();
    break;
case myenum::two:
    T::boo();
    break;
}

假设 T 同时具有 foo() 和 boo()。在两个基类中定义这两个函数(是否为空无所谓)

我猜你正在尝试做的是从派生类型调用一个基函数,我猜这是继承已经创建。

enum class myenum : int {one, two};

class mybase_1{
protected:
    void foo(){
        qDebug() << "foo in mybase_1 is called \n";
    }
};

class mybase_2{
protected:
    void foo(){
        qDebug() << "foo in mybase_2 is called\n";
    }
};

template <typename T>
class myderived : public T{
public:
    myderived(myenum _enm);
    void callMethods();
private:
    myenum enm;
};

template <typename T> myderived<T>::myderived(myenum _enm):enm{_enm}{
    qDebug() << "derived constructor\n";
}
template <typename T> void myderived<T>::callMethods(){
    foo(); // the foo called depends on the parameter supplied to template, which determines from which class your derived class has been derived.
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    myderived<mybase_1> tmp1(myenum::one);
    tmp1.callMethods();
    myderived<mybase_2> tmp2(myenum::two);
    tmp2.callMethods();

    return a.exec();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-04-01
    • 1970-01-01
    • 2013-11-21
    • 2017-09-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多