tags:

views:

200

answers:

2

I need a fresh pair of eyes.

This is obviously illegal, but it shows what I'm trying to do:

template <typename T, T> struct Foo
{
};

template <typename T> struct Foo <T, 0> //Obviously I can't do this.
{
};

Is there any way to wrap T or do something tricky so that this sort of thing can work?

Thanks!

+13  A: 

Yes, you can use this trick:

template <typename T, T, T=0> struct Foo {
};

template <typename T, T t> struct Foo <T, t, t> {
};

If t is 0 in the specialization, it will match the default argument, and the specialization is taken. Otherwise, the primary template is taken.

Edit: What the heck does the third parameter mean? Well, it's a default and it's 0. It will be passed when we name the specialization Foo<int, 5> for example. But really, we instantiate a template with the arguments Foo<int, 5, 0>, because the last is a default argument. The partial specialization matches, when the third parameter matches the third argument, which is zero by default, and if the third and second arguments are the same, because both are t.

The above trick has the drawback that also Foo<int, 9, 9> uses our specialization. But on the other side, the above is remarkable simple, so that you can probably get away with that. If you don't want that to work, then you can use enable_if, which is a bit more complicated:

template <typename T, T, typename = void> struct Foo {
};

template <typename T, T t> 
struct Foo <T, t, typename boost::enable_if_c< t == 0 >::type> {
};

Now, even if you say Foo<int, 9, void>, our partial specialization won't be chosen, because the condition t == 0 isn't true, and ::type will thus not be available. SFINAE doesn't chose the specialization then. Of course, with this enable_if solution, you are not limited to t being zero. Any condition will do. For reference, here is the code of enable_if, if you don't use boost. Cut the _c suffix above then, which we don't need for the version below:

template<bool C, typename T = void>
struct enable_if {
  typedef T type;
};

template<typename T>
struct enable_if<false, T> { };
Johannes Schaub - litb
I am not sure I understand this. What is the third argument for? Could you please clarify?
Hosam Aly
Do you mean, for the second one: template <typename T, T t=0> struct ... ?
strager
edited the stuff.
Johannes Schaub - litb
The third argument is there just to get a value 0 of type T in it.If you wanted to specialize for two values (like 0 and 1), you would have to use a type argument as described in the documentation of boost::enable_if, am I right?
jpalecek
yeah, exactly. like the one here, the conditions must be disjunct, so that you don't get ambiguities: http://stackoverflow.com/questions/267418/elegant-template-specialization#275254
Johannes Schaub - litb
Wow, nice trick litb!
j_random_hacker
A: 

@litb: Awesome trick, thanks.

@Adam: I was trying to have the 'n' be of type T. Maybe I asked wrong, but litb's solution works great for me.

What are you trying to do? Your example doesn't make a lot of sense.
Adam Rosenfield
I was playing around with template meta programming, specializing for zero to terminate the recursive nature of the algorithm while maintaining flexibility when it came to types.
@Philly37 - if you like litb's answer, you would normally click the star icon to mark it as the right answer, rather than just replying with another "answer". :)
Daniel Earwicker