tags:

views:

98

answers:

3

I want to have a template class that looks something like what I have down below. Then, I want a function in it with a template specialization depending on a CLASS template parameter. How do I make this work? I realize the code I provided is wrong on many levels, but it's just to illustrate the concept.

template <typename _T, size_t num>
class Foo
{
    // If num == 1, I want to call this function...
    void Func<_T, 1>()
    {
        printf("Hi!");
    }

    // Otherwise, I want to call this version.
    void Func<_T, num>()
    {
        printf("Hello world!");
    }
};
+1  A: 

There are no partial specialisations of function templates, and to partially specialise a member you need to first partially specialise the class template.

template< typename _T, size_t num >
struct Foo {
    void Func() {
        printf("Hello world!");
    }
};

template< typename _T >
struct Foo< _T, 1 > {
    void Func() {
        printf("Hi!");
    }
};

Now, if Foo also contains methods other than Func whose implementation is independent of the value for num, and you don't want to duplicate their implementation in the specialization of Foo, you can apply the following pattern:

template< typename _T, size_t num >
struct FooFuncBase {
    void Func() {
        printf("Hello world!");
    }
};

template< typename _T >
struct FooFuncBase< _T, 1 > {
    void Func() {
        printf("Hi!");
    }
};

template< typename _T, size_t num >
struct Foo : public FooFuncBase< _T, num > {
  void OtherFuncWhoseImplementationDoesNotDependOnNum() {
    ...
  }
};

Or, using CRTP:

template< typename _Derived, typename _T, size_t num >
struct FooFuncBase {
    void Func() {
        static_cast< _Derived* >(this)->OtherFuncWhoseImplementationDoesNotDependOnNum();
        printf("Hello world!");
    }
};

template< typename _Derived, typename _T >
struct FooFuncBase< _Derived, _T, 1 > {
    void Func() {
        static_cast< _Derived* >(this)->OtherFuncWhoseImplementationDoesNotDependOnNum();
        printf("Hi!");
    }
};

template< typename _T, size_t num >
struct Foo : public FooFuncBase< Foo< _T, num >, _T, num > {
  void OtherFuncWhoseImplementationDoesNotDependOnNum() {
    printf("Other");
  }
};
vladr
It is a class that is being specialised in this case, the OP just doesn't know how to write the syntax for that I think.
Michael Anderson
I think there's more to it, let's see what he answers. I'm almost certain he only needs to specialize a subset of `Foo`'s methods, not the entire class.
vladr
I like the solution, but I think it's quite hackish to put the "special case code" in the public interface and all the general code in the base. Surely there's a better way!
Clark Gaebel
What if Func depends on members declared in Foo?
Clark Gaebel
@wowus: http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
vladr
+1  A: 

This is called partial template specialisation. It looks like this:

template<typename _T, size_t num>
class FooBase
{
};

template <typename _T, size_t num>
class Foo : public FooBase<_T,num>
{
    void Func()
    {
        printf("Hello world!");
    }
};


template <typename _T>
class Foo<_T,1> : public FooBase<_T,num>
{
    void Func()
    {
        printf("Hi!");
    }
}
Michael Anderson
I don't want to duplicate the full body of Foo (there's many other methods in there that I've omitted) in each specialization.
Clark Gaebel
Edited to allow for functions in a base class.
Michael Anderson
+5  A: 
struct Otherwise { };
template<size_t> struct C : Otherwise { };

// don't use _Uppercase - those names are reserved for the implementation
// (i removed the '_' char)
template <typename T, size_t num>
class Foo
{
public:
    void Func() { Func(C<num>()); }

private:
    // If num == 1, I want to call this function...
    void Func(C<1>)
    {
        printf("Hi 1!");
    }

    // If num == 2, I want to call this function...
    void Func(C<2>)
    {
        printf("Hi 2!");
    }

    // Otherwise, I want to call this version.
    void Func(Otherwise)
    {
        printf("Hello world!");
    }

    //// alternative otherwise solution:
    // template<size_t I>
    // void Func(C<I>) { .. }
};
Johannes Schaub - litb
I like this solution. I even learned something about C++ naming convention! However, how do I do this if I have, say, any number of specializations for various values of num along with a fall-back in case none of them work?
Clark Gaebel
@wowus, updated answer
Johannes Schaub - litb
Thanks, accepted.
Clark Gaebel
Wow! Awesome! I may need to go refactor some code...
Narfanator
Wow that worked amazingly. Are you like, a boost developer or something? Templates are nasty beasts.
Clark Gaebel