0

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

I currently have a class declared / defined as such:

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

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

};

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.

I had tried something like this:

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

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.

Francis Cugler
  • 7,788
  • 2
  • 28
  • 59
  • You seem to be using `Other` sometimes as a template and sometimes as a type. That won't go well. – aschepler Mar 19 '18 at 23:41
  • @aschepler That's the trouble I'm having with the declarations/definitions. – Francis Cugler Mar 19 '18 at 23:42
  • I'm trying to write a single generic function template that will choose the appropriate function template from the 2nd class; however some of these function templates may have more than one template argument and the list of their parameters varies. With the engine it was easy as none of them were templates, and they all have the same 3 parameters. – Francis Cugler Mar 19 '18 at 23:44
  • In the end Other should be a class object; but for examples: `otherA a` could be one type while `otherB b`. where `a's` constructor might have `(int a, int b)` and `b's` constructor might have `( A a1, A a2, B b1 )`. I need to resolve all of the parameter types for my generic function template that will call these methods. – Francis Cugler Mar 19 '18 at 23:44
  • @aschepler I've changed the name of the class from `Other` to `SomeOther` so that the function declaration with the template parameter argument list of `class Other` doesn't confuse you or conflict; in my actual code they are not the same name. – Francis Cugler Mar 19 '18 at 23:54
  • A bit clearer, but in `generate()` the part with `SomeOther::getOther` doesn't make sense because the second template argument to `getOther` must be a template name. – aschepler Mar 20 '18 at 00:19
  • @aschepler that was a typo on my part: it is supposed to be `static Other other = SomeOther::getOther> ( params... ); ` It is now fixed in the code above. – Francis Cugler Mar 20 '18 at 00:21
  • @aschepler I don't know if I need to declare multiple overloads of `getOther` that have a different amount of template arguments and or function parameters; or if I'm able to resolve all of them into a single function declaration using variadic parameters. – Francis Cugler Mar 20 '18 at 00:32

1 Answers1

1

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

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.

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

and the output will be

I'm OtherA
AValue: 1
I'm OtherE
EValue: 3
dontpanic
  • 341
  • 2
  • 8
  • The concept above seems okay; but here is the issue: the other's that I'll be returning back are the different types of distributions found in the `` header file. These classes are already declared. I just wanted to `funnel` the types needed to return back the appropriate distribution. You see I have static functions to return each distribution by independent name such as `std::uniform_int_distribution& Bar::getUniformIntDistriubtion( IntType a, IntType b );` So I'm not trying to rewrite classes. I would like a single `getDistriubtion( params... );` function. – Francis Cugler Mar 20 '18 at 04:56
  • @FrancisCugler Sorry but I don't really catch the point. You don't need to rewrite `otherA`/`otherB`/etc.., but only have to change `Bar`. `Bar` is your own implementation, right? – dontpanic Mar 20 '18 at 05:29
  • Bar itself is a non template class that has nothing but static methods to get the different types of distributions. Each of the static methods themselves are already function templates. Now, I'm just trying to write a single function template to generically get the specific distribution based on the function templates argument list of which distribution was specified, then what type that distribution will use. – Francis Cugler Mar 20 '18 at 05:31
  • This older question might help you as it actually has my classes (at least partial parts of the classes). https://stackoverflow.com/questions/49336082/class-member-function-template-partial-specialization-with-variadic-parameters – Francis Cugler Mar 20 '18 at 05:34
  • @FrancisCugler I still didn't see any difference when `otherA` is `std::uniform_int_distribution`. What you did before is to specialize the template for every distribution, and now, you have to write a series of overloading for every distribution. Did I lose sight of anything? – dontpanic Mar 20 '18 at 11:21
  • I was thinking of trying to use templates; with template argument deduction to simplify the code, but in order to make a single generic function; I have to write the specialization of each and every kind of distribution for each and every type that it will support which is leading to code bloat... However; the user end of the code would be much easier... but the back end or library end will be quite cumbersome with all of the overloads and specializations... ehh – Francis Cugler Mar 20 '18 at 12:04