Sergey
Sergey

Reputation: 8238

Specialization for identical template parameters

I have a function template:

//the most generalized template 
template<typename typeArg, typename typeRet>
typeRet func(const typeArg &val);

and several specializations for it, which look like:

template<>
someType func(const otherType &val)
{
    //code
}

template<>
typeFoo func(const typeBar &val)
{
    //more code
}

but it has no default implementation.

Obviously, both types cannot be deduced automatically, so calls look like:

type1 var1 = func<argType,type1>(arg);

What is the proper way to write a default implementation only for the case when types are identical?

I tried some variants:

1st attempt

template<typename theOnlyType, theOnlyType>
theOnlyType func(const typeArg &theOnlyType)
{
    //code
}

But it's wrong, because this function has only one template parameter and it doesn't correspond to the call above.

2nd attempt

template<typename type1, typename type2>
type1 func(const type1 &theOnlyType)
{
    //code
}

The call becomes ambiguous, candidates are this function and the most generalized template from the first block of code.

Upvotes: 2

Views: 234

Answers (1)

David G
David G

Reputation: 96800

After a bit of studying I've come up with a significantly better solution. It involves adding a wrapper class around static methods and dispatching them through a global method:

#include <iostream>

namespace tag
{
    template <typename U, typename P>
    struct wrapper // default implementation
    {
        static U foo(P const &)
        {
            std::cout << "different types";
            return U();
        }
    };
}

namespace tag
{
    template <typename T>
    struct wrapper<T, T> // specialized
    {
        static T foo(T const &)
        {
            std::cout << "same type";
            return T();
        }
    };
}

template <typename U, typename P>
static inline U foo(P const &p)
{
    return tag::wrapper<U, P>::foo(p);
}

int main()
{
    foo<int>(0);
    foo<int>(true);
}

I hope this helps.


Use std::enable_if with std::is_same (C++11):

template <typename A, typename B, typename = 
          typename std::enable_if<std::is_same<A, B>::value>::type> 
B foo(const A &) {

}

Or use this version for C++03 and earlier:

template <typename A, typename B> struct foo; // implement for different types

template <typename T> struct foo<T, T> {
    T operator()(const T &) {
        // default impelentation
    }
};

int main() {

    foo<int, int> f;
    int n;

    f( n );

}

I'm sure there's a way to improve this. I tried to use partial specialization with the function but I couldn't get it to work for me.

Upvotes: 3

Related Questions