Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specialize template based on positivity of argument

Given a template

template <int n>
void f(){...};

I know I can specialize it for specific values of n by doing:

template <>
void f<2>(){...};

But, is there a method which allows me to specialize it for all positive n?

I thought of doing the following

template <int n>
void f<n>(){
    int dummy[n]; //invalid for n < 0
    ...
};

So for n<0 this code is invalid and the compiler would resort to the previous definition. Unfortunately, all I get is a redefinition of 'void f<n>()' error.

Note: I'm guessing this is probably not supported by the standard. I'm asking if there isn't some method (maybe some template metaprogramming) to achieve this effect.

like image 257
Malabarba Avatar asked Apr 04 '12 19:04

Malabarba


People also ask

What is a template argument?

A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.

What is meant by template specialization?

The act of creating a new definition of a function, class, or member of a class from a template declaration and one or more template arguments is called template instantiation. The definition created from a template instantiation is called a specialization.

Why do you need class template?

Class templates are generally used to implement containers. A class template is instantiated by passing a given set of types to it as template arguments. The C++ Standard Library contains many class templates, in particular the containers adapted from the Standard Template Library, such as vector .

How a class template can be declared?

A class template must be declared before any instantiation of a corresponding template class. A class template definition can only appear once in any single translation unit. A class template must be defined before any use of a template class that requires the size of the class or refers to members of the class.


1 Answers

One option would be to use another level of indirection. Define an auxiliary template that takes in two arguments - the number n and a bool representing whether or not n is negative, then specialize that template for when n is negative. Then, have your f function instantiate the template with the right arguments.

For example:

template <int n, bool isNegative> struct fImpl {
    static void f() {
       /* ... code for when n is positive ... */
    }
};
template <int n> struct fImpl<n, true> {
    static void f() {
       /* ... code for when n is negative ... */
    }
};

template <int n> void f() {
    fImpl<n, (n < 0)>::f();
}

Another option is to use SFINAE overloading and the std::enable_if template class from C++11 (or Boost's equivalent);

template <int n> void f(typename std::enable_if<(n < 0)>::type* = 0) {
    /* ... n is negative ... */
}

template <int n> void f(typename std::enable_if<(n >= 0)>::type* = 0) {
    /* ... n is positive ... */
}

Each of these functions will only be available for overload resolution if n has the proper sign, so the correct version will always be called.

Hope this helps!

like image 50
templatetypedef Avatar answered Oct 26 '22 23:10

templatetypedef