Sign in to follow this  
ascorbic

C++ Class Template Specialization

Recommended Posts

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!

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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 =)

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this