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