0

I have 2 classes that follow a similar pattern:

Foo.h

// header guard here 

class Foo {
public:
    Foo() = delete;

    static foo1& getFoo1( Param a, Param b, Param c ) {
        // code...
    }

    static foo2& getFoo2( Param a, Param b, Param c ) {
        // code...
    }

    // generic function to return appropriate Foo Type based on template argument 
    template<class FooType>
    static FooType& getFoo( Param a, Param b, Param c );
};

#endif

Foo.cpp

#include <Foo.h>

// specializations of getFoo() for each type
template<>
foo1& Foo::getFoo( Param a, Param b, Param c ) {
    return getFoo1( a, b, c );
}

template<>
foo2& Foo::getFoo( Param a, Param b, Param c ) {
    return getFoo2( a, b, c );
}

Foo above compiles just fine. Bar on the other hand has a similar structure or pattern as Foo above; the only difference is that it's static getBar1(), getBar2() etc. are not just normal functions; they are function templates.

Bar.h

// header guard

class Bar {
public:
    Bar() = delete;

    template<class IntType = int>
    static bar1<IntType>& getBar1( IntType a, IntType b ) {
        // code...
    }

    template<class RealType = double>
    static bar2<RealType>& getBar2( RealType a, RealType b ) {
        // code...
    }

    template<class IntType = int>
    static bar3<IntType>& getBar3( IntType a ) {
        // code...
    }

    template<class RealType = double>
    static bar4<RealType>& getBar4( RealType a ) {
        // code...
    }

    // ...

    template<class RealType = double>
    static bar12<RealType>& getBar12() {
        // code...
    }

    template<class RealType = double, class A, class B>
    static bar12&<RealType>& getBar12( A a1, A a2, B b1 ) {
        // code...
    }

    template<class RealType = double, class X>
    static bar12&<RealType>& getBar12( std::initialize_list<double> list, X x ) {
        // code...
    }

    template<class RealType = double, class X>
    static bar12&<RealType>& getBar12( std::size_t size, RealType a, RealType b, X x ) {
        // code..
    }

    // Here is where I start to get into problems:
    // I'm trying to do something similar to what I've done above in Foo for a generic function template.
    template<typename Type, template<typename> class BarType, class... FuncParams>
    static BarType<Type>& getBar( FuncParams... params );

}; 

#endif

Bar.cpp

#include "Bar.h"

// specializations of getBar() for each type
template<typename Type, class... FuncParams>
bar1<Type>& Bar::getBar( FuncParams... params ) {
    return getBar1( params... );
}

template<typename Type, class... FuncParms>
bar2<Type>& Bar::getBar( FuncParams... params ) {
    return getBar2( params... );
}

Why is it that when I begin to added a class type that is a class template; everything seems to break. The first class above compiles and returns back the appropriate Foo. However, in the second class Bar I keep getting compiler errors that function definition is not matching an existing declaration.

This question is related to this one here: Specializing and or Overloading member function templates with variadic parameters

This question is specifically about why the one does compile and the other one doesn't.

max66
  • 65,235
  • 10
  • 71
  • 111
Francis Cugler
  • 7,788
  • 2
  • 28
  • 59

1 Answers1

2

The first class above compiles and returns back the appropriate Foo

Yes, because

template<>
foo1& Foo::getFoo( Param a, Param b, Param c ) {
    return getFoo1( a, b, c );
}

it's a full specialization of the template method getFoo()

template<class FooType>
static FooType& getFoo( Param a, Param b, Param c );

with the FooType type fixed to foo1.

And you can make a full specialization of a template function (or method).

However, in the second class Bar I keep getting compiler errors that function definition is not matching an existing declaration.

Sure.

Because you're trying to partial specialize the template method getBar()

template<typename Type, template<typename> class BarType, class... FuncParams>
static BarType<Type>& getBar( FuncParams... params );

fixing BarType to bar1

template<typename Type, class... FuncParams>
bar1<Type>& Bar::getBar( FuncParams... params ) {
    return {};//getBar1( params... );
}

But you can't partial specialize a template function/method. It's forbidden by the language.

If you want something similar, you have to pass through the partial specialization of a struct (or class).

--- EDIT ---

The OP ask

You said, "you have to pass through the partial specialization of a struct( or class)." Okay; so there is a work around: would you be able to provide a small basic example?

There are many ways to use partial specialization of structs (classes) to bypass the non-partial-specialization limits for functions/methods.

In the following basic example I propose a template foo struct with a template func() method. The single template parameter for foo is the type returned by func(); the variadic template type list for func() is the list of types of arguments.

But you can play this game in differents modes.

#include <iostream>

template <typename>
struct bar1
 { template <typename ... Args> bar1 (Args && ...) { } };

template <typename>
struct bar2
 { template <typename ... Args> bar2 (Args && ...) { } };

template <typename>
struct foo;

template <typename T>
struct foo<bar1<T>>
 {
   template <typename ... Args>
   static bar1<T> func (Args && ... as)
    { return { std::forward<Args>(as)... }; }
 };

template <typename T>
struct foo<bar2<T>>
 {
   template <typename ... Args>
   static bar2<T> func (Args && ... as)
    { return { std::forward<Args>(as)... }; }
 };

int main()
 {
   foo<bar1<int>>::func(1, "two", 3.0);
   foo<bar2<long>>::func(4.0f, "five", 6L);
 }
max66
  • 65,235
  • 10
  • 71
  • 111
  • I think partial specialization should be written as `Bar::getBar(){...}`. IMO In this case the compiler is just trying to find a matching declaration but fails. – dontpanic Mar 20 '18 at 04:02
  • Thank you for the detailed explanation. This is where I was having trouble; I didn't know if I had incorrect syntax or if it couldn't be done. You said, "you have to pass through the partial specialization of a struct( or class)." Okay; so there is a work around: would you be able to provide a small basic example? – Francis Cugler Mar 20 '18 at 04:39
  • @dontpanic - C++ doesn't allow partial specialization for functions/methods – max66 Mar 20 '18 at 13:14
  • @FrancisCugler - answer improved with a little example; hope this helps. – max66 Mar 20 '18 at 13:15
  • @max66 Yes. I mean writing in that way isn't partial specialization at all. – dontpanic Mar 20 '18 at 15:04
  • Well I know that `partial specialization` of function templates are not valid in C++, but trough the use of specialization through classes, you can sort of mimic the idea of it. It is sort of a work around to overload methods not based on their actual parameter list, but based on their returns. This is where the power of templates comes into play; otherwise you would not be able to resolve overload resolution based on the return type alone giving you ambiguous function name lookups and function calls especially if the return value is not used. I don't know what to call this template pattern. – Francis Cugler Mar 20 '18 at 18:40