簡體   English   中英

使用可變參數專門化和/或重載成員函數模板

[英]Specializing and or Overloading member function templates with variadic parameters

嘗試解決類成員的重載解決方案:靜態函數模板重載-部分專業化。

我目前有一個這樣聲明/定義的類:

注意:我對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

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()調用來使類專門化以返回適當的Engine Type,從而可以正常工作。 我有一個非類成員函數模板, class Engineclass 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 );

然后,我上面顯示的功能還沒有完成,在添加對第二類的支持時,我嘗試了以下操作:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM