C++ Class Template Specialization

Started by
4 comments, last by Sneftel 16 years, 10 months ago
I have a simple question about templates that I hope has a similarly simple answer. Suppose I have a class defined as below:

template<class T>
class foo
{
    public:
        T bar(T);  // works fine

    private:
        // MY ATTEMPTS AT SOLVING MY PROBLEM
        double bar(double);       // C2535 : member function already defined
        template<> double bar(double);  // compiles, but obviously not right
};

foo<int> i;
foo<double> d;
int a = 2;
double b = 3.0;
i.bar(a);   // should work - int should be public
d.bar(b);   // should not work - double should be private
How do I do the specialization so that, for example, if T is a double, then the function is private? Only a double should not be defined as public. I've tried a couple of ways to approach the problem, but no. Is this even possible? If I need to explain the question better, please let me know. As always, thanks for your help in advance!
.
Advertisement
Templates, unfortunately, don't provide an especially concise way to say "any type except Foo". There are ways to make the public usage of bar(double) impossible, but most of them make private usage impossible as well. What is the real-world situation you're faced with?
You can specialize the entire template to achive that.

template<>class foo<double>{	private:		double bar(double);};


But as Sneftel said, you might want to tell us what you really want to do =)
The only way I know of to achieve the exact behavior mentioned without specializing the whole class is to split it into two functions, a public version which will work for all types but double and a private version for double's but you have to implement it twice if you do this, if the implementation is similar enough you can just create a third function for both versions to call though.

How it works:

When you access a nested member of a type that is dependent on a template parameter during overload resolution and the member doesn't exist the compiler doesnt trigger an error but simply removes it from the list of possible overloads so we can write a template which provides the member for everything but doubles, something like the following:

template<typename T>struct disable_for_doubles{    typedef T type;};template<>struct disable_for_doubles<double>{ };


and use disable_for_doubles<T>::type as the returns type for our function which will prevent it being used for T == double. Of coarse witting lots of these is extremely repetitive so boost.enable_if provides a template enable_if and disable_if which wrap up the details for you.

#include <boost/type_traits/is_same.hpp>#include <boost/enable_if.hpp>template<typename T>struct foo{        boost::disable_if<boost::is_same<T, double>, T>::type        bar(T t);    private:        double bar(double);};


Of coarse with more details it might be possible to provide a less verbose solution.

Edit: Forgot to mention the technique is called SFINAE
Thanks so far for all your responses. There really is no real world problem that I need to address. This was a tricky interview question I had that I couldn't figure out the answer to. It's very possible I just don't remember the exact question very well.

Sneftel mentioned that there are ways to make the public usage of bar(double) impossible. This is probably all the interviewers were looking for. How would you go about doing this?

Also, is there a specific small project that one can do to learn templates in better detail than just writing a stack or queue class?
.
The basic idea is to delegate the error to an "error on double" class. Watch:

template<class T>class ErrorIfDouble(){public:    ErrorIfDouble() { }};template<>class ErrorIfDouble<double>(){private:    ErrorIfDouble() { }};template<class T>class foo{public:    T bar(T a)    {        ErrorIfDouble<T>();        return bar_impl(a);    }private:    T bar_impl(T);};

And hey presto, any attempt to call foo<double>::bar will cause the instantiation of the specialized ErrorIfDouble<double>, which isn't allowed and will cause an error. That error will refer to ErrorIfDouble::ErrorIfDouble() as the offending function rather than foo::bar, but at least it has the right behavior. There are many other ways of accomplishing this sort of thing, but they all pretty much come down to doing something stupid in a template specialization or as the result of a template specialization.

This topic is closed to new replies.

Advertisement