使用可变参数专门化和/或重载成员函数模板 [英] Specializing and or Overloading member function templates with variadic parameters

查看:133
本文介绍了使用可变参数专门化和/或重载成员函数模板的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Trying to resolve overload resolution for class member: static function template overload - partial specialization.

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

I currently have a class declared / defined as such:

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

Note: my use of Param a, Param b, Param c etc. are not related to the actual declarations / definitions directly. These can be any arbitrary type that is passed into the functions for example: it could be int a, enum b, char c. I'm just using this to only show the pattern of the declarations, however all of the different engines take the same 3 different parameters.

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

SomeEngine.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作为其模板参数之一...这是在任何类之外的同一标题中以及将使用的前两个类之后定义的.

The above design pattern for the function template where I was able to specialize the class to return the appropriate Engine Type using a single generic getEngine() call compiles and works fine. I have a non class member function template that takes a class Engine as one of its template parameters... This is defined in the same header above outside of any class and after the first two classes that it will use.

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 );
}

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

And the above works except the function shown here is not complete. It relies on another class. The other class itself has a similar pattern as the one above; it has a deleted default constructor, and a bunch of static methods to return the different types of objects; however in the 2nd class, almost all of the static methods themselves are function templates, some have overloaded versions while others have more than one template parameter. It is also declared in the same header file above. It looks something like this:

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依赖于其自己的模板参数和内部函数调用可能具有不同数量的参数.

I'm trying to do something similar with the 2nd class above to have a generic function template such that I can pass to it the template parameter class Other except that class Other depends on its own template arguments and the internal function calls may have a different amount of parameters.

这使我开始使用可变参数模板来声明此类的功能.

This was leading me into the use of variadic templates for the declarations of this class's function.

我尝试过这样的事情:

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

然后我上面显示的功能还不完整,我在添加对第二类的支持时尝试了此操作:

And then my function that I've shown above that was not complete I tried this when adding in the support for the 2nd class:

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()函数的尝试

This is how I would be using the 2nd class above. Here are my attempts of trying to specialize a couple of the getOther() functions in the corresponding cpp file

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... );
}

这不能编译,它抱怨函数定义与现有的声明不匹配.我什至试图在头文件中写一个重载,并且不断出现相同的错误.我不知道这是否是语法错误.我已经尝试了很多要在此处列出的内容,我在各处搜索了相似的内容,但似乎找不到任何相关的内容.

This doesn't compile it complains that the function definition does not match an existing declaration. I even tried to write an overload in the header file and I keep getting the same errors. I don't know if it is a syntax error or not. I've tried far to many things to list here, I've searched all over the place looking for something similar but can not seem to find anything relevant.

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

I would like to know if something like this can be done; and if so what needs to be changed above in order for it to at least compile and build; so I can start to test it during runtime; then move on to add other existing types.

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

I would like to try and keep the same design pattern of the first class with the 2nd. My stand alone function template is the function that will be called and depending on it's template parameters; it should know which engine - other types to call.

推荐答案

在第二种情况下,实际上您不是尝试部分专业化getOther.部分专业化应该这样写:

In you second case, actually you are not trying to partial specialize getOther. Partial specialization should be written like this:

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会显示错误消息:

and GCC will give an error saying:

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

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

So in your second case, you are actually implementing the method that you declared before and the compiler fails to find a matching declaration.

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

In order to solve this issue, as partial specialization is not allowed by C++, you can use Function Overloading. Here is an example (it compiles on GCC but fails to compile on VS2017, more like an issue of MSVC but I'm not sure):

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

这篇关于使用可变参数专门化和/或重载成员函数模板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆