c++ - 无法从模板类内的模板函数类调​​用类函数

标签 c++ templates design-patterns

我正在尝试创建一个模式,其中抽象类具有几种方法,所有方法都具有相同的成员。派生的实现基于特定的成员类型,该模式应减少向下转换类型的需求。
以下内容无效:
假设这些类型类

//--------------
// Data classes
//--------------
class TypeA
{
    virtual int a() = 0;
};

class TypeB : public TypeA
{
    int a() override
    {
        return 5;
    }
};
模式:
//-------------------
// Base action class.
//-------------------
class ExampleBase
{
public:
    virtual bool f1(TypeA& val) = 0;

    virtual bool f2(TypeA& val) = 0;
};

//----------------------------------
// Base specific Typed action class.
//----------------------------------
template<class T>
class ExampleSpecific1 : public ExampleBase
{
public:
    virtual bool specificF1(T& specificVal) = 0;

    virtual bool specificF2(T& specificVal) = 0;

    bool f1(TypeA& val) override
    {
        return fRunner<bool, specificF1>(val, false);
    }

    bool f2(TypeA& val) override
    {
        return fRunner<bool, specificF2>(val, false);
    }

private:

    // Run the specific function with the specific type
    template<class S, S (*pf)(T& val)>
    S fRunner(TypeA& val, S defaultValue)
    {
        S ret = defaultValue;
        T& specificVal = dynamic_cast<T&>(val);

        if (&specificVal != nullptr) {
            ret = pf(specificVal);
        }

        return ret;
    }
};
实现
//----------------------
// Class Implementation.
//----------------------
class ExampleImpl : public ExampleSpecific1<TypeB>
{
public:
    bool specificF1(TypeB& specificVal) override
    {
        // Do something
    }

    bool specificF2(TypeB& specificVal) override
    {
        // Do something
    }
};
用法:
//-----------
// Class Use.
//-----------
void main()
{
    ExampleImpl impl;
    TypeB myVal;

    TypeA& myBaseVal = myVal;
    impl.f1(myBaseVal);
    impl.f2(myBaseVal);
}
我收到以下编译错误:
error C2672: 'ExampleSpecific1<TypeB>::fRunner': no matching overloaded function found
note: while compiling class template member function 'bool ExampleSpecific1<TypeB>::f2(TypeA &)'
note: see reference to function template instantiation 'bool ExampleSpecific1<TypeB>::f2(TypeA &)' being compiled
note: see reference to class template instantiation 'ExampleSpecific1<TypeB>' being compiled
error C2975: 'pf': invalid template argument for 'ExampleSpecific1<TypeB>::fRunner', expected compile-time constant expression
note: see declaration of 'pf'
有效的函数模板(当函数不在类内时):
根据前面的示例:
template<class T, bool (*pf1)(T& Val), bool (*pf2)(T& Val)>
class ExampleSpecific2 : public ExampleBase
{
public:
    bool f1(TypeA& val) override
    {
        bool ret = false;
        T& specificVal = dynamic_cast<T&>(val);

        if (&specificVal != nullptr) {
            ret = pf1(specificVal);
        }
        return ret;
    }

    bool f2(TypeA& val) override
    {
        bool ret = false;
        T& specificVal = dynamic_cast< T&>(val);

        if (&specificVal != nullptr) {
            ret = pf2(specificVal);
        }
        return ret;
    }
};
外部功能:
bool extF1(TypeB& val)
{
    // Do something.
}

bool extF2(TypeB& val)
{
    // Do something.
}
用途:
//-----------
// Class Use.
//-----------
void main()
{
    TypeB myVal;
    TypeA& myBaseVal = myVal;

    ExampleSpecific2<TypeB, extF1, extF2> impl2;

    impl2.f1(myBaseVal);
    impl2.f2(myBaseVal);
}
在不起作用的示例中,我可以在每个实现中都实现向下转换,然后再起作用,但是它很丑陋,并且不是通用的。在工作示例中,我希望函数在类的内部实现中而不在其外部,这在更复杂的场景中很重要,在复杂的场景中,基类正在调用多个派生方法。
  • 顺便说一句,我不喜欢这篇文章的标题,如果您有一个更好的建议,我会喜欢。
  • 最佳答案

    注意 :

  • main应该返回一个int,而不是void
  • if (&specificVal != nullptr)将始终为true,引用不能为null。

  • 我不知道为什么您收到此错误消息,并得到gcc:
    no matching member function for call to 'fRunner'
    
    因为pf类型是bool (ExampleSpecific1<TypeB>::*)(TypeB &)S (*pf)(T& val)不匹配。第一个需要一个类对象。
    所以我只用C++ 17 auto:
    template<class S, auto pf>
    S fRunner(TypeA& val, S defaultValue){...}
    
    但是,您可以根据需要使用完整类型。
    下一步我们需要调用成员函数。我不喜欢(也不记得)成员函数调用语法,所以我只使用C++ 17的std::invoke。 (请参阅:https://en.cppreference.com/w/cpp/utility/functional/invoke)
    现场直播:https://wandbox.org/permlink/rEqgLSwSjEfqRK2o
    #include <iostream>
    #include <vector>
    //--------------
    // Data classes
    //--------------
    class TypeA
    {
        virtual int a() = 0;
    };
    
    class TypeB : public TypeA
    {
        int a() override
        {
            return 5;
        }
    };
    
    
    
    //-------------------
    // Base action class.
    //-------------------
    class ExampleBase
    {
    public:
        virtual bool f1(TypeA& val) = 0;
    
        virtual bool f2(TypeA& val) = 0;
    };
    
    //----------------------------------
    // Base specific Typed action class.
    //----------------------------------
    template<class T>
    class ExampleSpecific1 : public ExampleBase
    {
    private:
    
        // Run the specific function with the specific type
        template<class S, auto pf>
        S fRunner(TypeA& val, S defaultValue)
        {
            S ret = defaultValue;
            T& specificVal = dynamic_cast<T&>(val);
     
            ret = std::invoke(pf, *this, specificVal);
    
    
            return ret;
        }
    public:
        virtual bool specificF1(T& specificVal) = 0;
    
        virtual bool specificF2(T& specificVal) = 0;
    
        bool f1(TypeA& val) override
        {
            return this->fRunner<bool, &ExampleSpecific1<T>::specificF1>(val, false);
        }
    
        bool f2(TypeA& val) override
        {
            return this->fRunner<bool, &ExampleSpecific1<T>::specificF2>(val, false);
        }
    
    
    };
    
    // Class Implementation.
    //----------------------
    class ExampleImpl : public ExampleSpecific1<TypeB>
    {
    public:
        bool specificF1(TypeB& ) override
        {
           std::cout << "specificF1" << std::endl;
           return true;
        }
    
        bool specificF2(TypeB& ) override
        {
            std::cout << "specificF2" << std::endl;
           return true;
        }
    };
    
    
    
    //-----------
    // Class Use.
    //-----------
    int main()
    {
        ExampleImpl impl;
        TypeB myVal;
    
        TypeA& myBaseVal = myVal;
        impl.f1(myBaseVal);
        impl.f2(myBaseVal);
    }
    
    C++ 17之前的版本:https://wandbox.org/permlink/HSGMy4zb4TgusESf
    template<class S, S (ExampleSpecific1<T>::*pf)(T &)> // full type since auto is C++ 17
    S fRunner(TypeA& val, S defaultValue)
    {
         S ret = defaultValue;
         T& specificVal = dynamic_cast<T&>(val);
         ret = (this->*pf)(specificVal); // Ugly pre 17 
    
         return ret;
    }
    

    关于c++ - 无法从模板类内的模板函数类调​​用类函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63825642/

    相关文章:

    C++ 模板实例化点困惑

    templates - 如何在 Rust 中使用数值作为泛型参数?

    java - 使用访问者模式和界面有什么区别?

    c++ - 避免 "if failed cleanup"重复的模式

    c++ - 使用 C++ 和 openCV 进行立方体检测

    c++ - “newacc”不是类或 namespace

    c++ - 文件内容写入队列并统计元音字母的个数

    c++ - 是否可以对 dll 进行更改,同时保持与预编译的可执行文件的兼容性?

    c++ - 使用模板类参数的模板类特化

    C++ 维度分析(Barnes 和 Nackman)与 Scale