专用和/或重载具有可变参数的成员函数模板

Specializing and or Overloading member function templates with variadic parameters

本文关键字:参数 变参 成员 函数模板 重载 专用      更新时间:2023-10-16

正在尝试解决类成员的重载解决方案:静态函数模板重载 - 部分专用化。

我目前有一个声明/定义的类:

注意:我对Param aParam bParam c等的使用与实际的声明/定义没有直接关系。这些可以是传递到函数中的任何任意类型,例如:它可以是int aenum bchar c。我只是使用它来仅显示声明的模式,但是所有不同的引擎都采用相同的 3 个不同参数。

SomeEngine.h

#ifndef SOME_ENGINE_H
#define SOME_ENGINE_H
class SomeEngine {
public:
SomeEngine() = delete;
static engineA& getEngineA( Param a, Param b, Param c );
static engineB& getEngineB( Param a, Param b, Param c );
// ... more static functions to return other engines
template<class Engine>
static Engine& getEngine( Param a, Param b, Param c );
};
// Another class
// function template that uses both classes above
#endif // SOME_ENGINE_H

某引擎.cpp

#include "SomeEngine.h"
template<>
EngineA& SomeEngine::getEngine( Param a, Param b, Param c ) {
return getEngineA( a, b, c );
}
template<>
EngineB& SomeEngine::getEngine( Param a, Param b, Param c ) {
return getEngineB( a, b, c );
}

上述函数模板的设计模式,我能够专门化类以使用单个泛型getEngine()调用返回适当的引擎类型,编译并工作正常。我有一个非类成员函数模板,它将class Engine作为其模板参数之一......这是在任何类之外的同一标头中定义的,并且在它将使用的前两个类之后。

template<class Engine, typename T>
T generateVal( Param a, Param b, Param c ) {
static T retVal = 0;
static Engine engine = SomeEngine::getEngine<Engine>( a, b , c );
}

并且上述工作除了此处显示的功能不完整。它依赖于另一个类。另一个类本身具有与上述类似的模式;它有一个已删除的默认构造函数,以及一堆静态方法来返回不同类型的对象;但是在第二类中,几乎所有静态方法本身都是函数模板,有些具有重载版本,而另一些则具有多个模板参数。它也在上面的同一头文件中声明。它看起来像这样:

class SomeOther {
public:
SomeOther() = delete;
template<class IntType = int>
static otherA<IntType>& getOtherA( IntType a, IntType b );
template<class RealType = double>
static otherB<RealType>& getOtherB( RealType a, RealType B );
template<class IntType = int>
static otherC<IntType>& getOtherC( IntType a );
template<class RealType = double>
static otherD<RealType>& getOtherD( RealType a );
template<class IntType = int>
static otherE<IntType>& getOtherE();
template<class IntType = int>
static otherE<IntType>& getOtherE( IntType a, IntType b );
template<class IntType = int>
static otherE<IntType>& getOtherE( std::initializer_list<double> a );
template<class IntType = int, class X>
static otherE<IntType>& getOtherE( std::size_t a, double b, double c, X x );
};

我正在尝试对上面的第二个类做类似的事情,以拥有一个通用函数模板,以便我可以将模板参数传递给它class Other,除了class Other依赖于它自己的模板参数,并且内部函数调用可能具有不同数量的参数。

这引导我使用可变参数模板来声明此类函数

。我试过这样的事情:

template< typename Type, 
template<typename, class...> class Other,
class... OtherParams, 
class... FuncParams> 
static Other<Type, OtherParams...>& getOther( FuncParams... params );

然后我上面显示的功能不完整,我在添加对 2nd 类的支持时尝试了这个:

template< class Engine, 
typename Type, 
template<typename, class...> class Other,
class... OtherParams,
class... FuncParams>
Type generate( Param a, Param b, Param c, FuncParams... params ) {
static Type retVal = 0;
static Engine engine = SomeEngine::getEngine<Engine>( a, b, c );
static Other<Type, OtherParams...> other = SomeOther::getOther<Type, Other<Type, OtherParams...>> ( params... );
retVal = other( engine );
return retVal;
}

这就是我使用上面的第二类的方式。以下是我尝试在相应的 cpp 文件中专门化几个 getOther() 函数的尝试

template<typename Type,
template<typename, class...> class Other,
class... OtherParams,
class... FuncParams>
otherA<Type>& SomeOther::getOther( FP... params ) {
return getOtherA( params... );
}
template<typename Type,
template<typename, class...> class Other,
class... OtherParams,
class... FuncParams>
otherB<Type>& SomeOther::getOther( FP... params ) {
return getOtherB( params... );
}

这不会编译它抱怨函数定义与现有声明不匹配。我什至尝试在头文件中写入重载,但不断收到相同的错误。我不知道这是否是语法错误。我已经尝试了很多东西在这里列出,我到处寻找类似的东西,但似乎找不到任何相关的东西。

我想知道是否可以做这样的事情;如果是这样,上面需要更改什么才能使其至少编译和构建;这样我就可以在运行时开始测试它;然后继续添加其他现有类型。

我想尝试与第二类保持与第一类相同的设计模式。我的独立函数模板是将被调用的函数,具体取决于它的模板参数;它应该知道哪个引擎 - 要调用的其他类型的引擎。

在第二种情况下,实际上您并没有试图部分专业化getOther。部分专业化应该这样写:

class Tmp
{
public:
template<class A, class B>
void bar(A a, B b) {}
};

template<class A>
void Tmp::bar<A, int>(A a, int b) {}

GCC 会给出一个错误,说:

error: non-class, non-variable partial specialization 'bar<A, int>' is not allowed
void Tmp::bar<A, int>(A a, int b) {}

因此,在第二种情况下,您实际上是在实现之前声明的方法,并且编译器无法找到匹配的声明。

为了解决这个问题,由于C++不允许部分专用化,因此可以使用函数重载。这是一个示例(它在 GCC 上编译,但无法在 VS2017 上编译,更像是 MSVC 的问题,但我不确定):

template <class T>
class otherA 
{
T t;
public:
otherA(T t) : t(t) {}
void WhoAmI() { cout << "I'm OtherA" << endl; }
T getValue() { return t; }
};
template <class T, class X>
class otherE 
{
T t;
public:
otherE(T t) : t(t) {}
void WhoAmI() { cout << "I'm OtherE" << endl; }
T getValue() { return t; }
};
class SomeOther {
public:
SomeOther() = delete;
template<class IntType = int>
static otherA<IntType>& getOtherA(IntType a, IntType b) 
{
static otherA<IntType> A(a);
return A;
}
template<class IntType = int, class X>
static otherE<IntType, X>& getOtherE(IntType a, double b, double c, X x)
{
static otherE<IntType, X> E(a);
return E;
}
template<template<typename, class...> class Other,
class Type,
class... OtherParams,
class... FuncParams>
static Other<Type, OtherParams...>& getOther(FuncParams... params)
{
return getOther<Type, OtherParams...>(params...);
}
private:
/// Function Overloading
template<class T,
class... FuncParams>
static otherA<T>& getOther(FuncParams... params)
{
return getOtherA<T>(params...);
}
template<class T,
class X,
class... FuncParams>
static otherE<T, X>& getOther(FuncParams... params)
{
return getOtherE<T, X>(params...);
}
};
template<
class Type,
template<typename, class...> class Other,
class... OtherParams,
class... FuncParams>
Type test(FuncParams... params) {
static Other<Type, OtherParams...>& other = SomeOther::getOther<Other, Type, OtherParams...>(params...);
other.WhoAmI();
return other.getValue();
}
class foo{};
int main()
{
int AValue = test<int, otherA>(1, 2);
cout << "AValue: " << AValue << endl;
int EValue = test<int, otherE, foo>(3, 2.1, 2.2, foo());
cout << "EValue: " << EValue << endl;
return 0;
}

输出将是

I'm OtherA
AValue: 1
I'm OtherE
EValue: 3