Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++ enable_if for non-type template parameters

I'm a bit confused about partial template specialization... I have some code that depends on an arithmetic data type T, and on a small integer DIM. I want to be able to specify different class methods for different values of DIM. The impossibility of using partial template specialization led me to explore enable_if. It's exactly what I needed... except I want it to return a number and not a type. How can I do that? The following code should illustrate what I want.

#include <stdio.h>
#include <iostream>
#include <type_traits>

template <typename T, int DIM>
class foo{
    public:
        T function();

};


template <typename T, int DIM>
T foo<T, std::enable_if<DIM == 1>::value>::function(){
    // do something
    return 1.0;
}

template <typename T, int DIM>
T foo<T, std::enable_if<DIM == 2>::value>::function(){  
    // do something else
    return 2342.0;
}

int main(){
    foo<int, 1> object;
    int ak = object.function();
    std::cout << ak << "\n";

    return 0;   
}
like image 415
Sermal Avatar asked Dec 19 '17 02:12

Sermal


People also ask

Which parameter is allowed for non-type template?

Which parameter is legal for non-type template? Explanation: The following are legal for non-type template parameters:integral or enumeration type, Pointer to object or pointer to function, Reference to object or reference to function, Pointer to member.

Can we use non-type parameters as arguments template?

Non-type template arguments are normally used to initialize a class or to specify the sizes of class members. For non-type integral arguments, the instance argument matches the corresponding template parameter as long as the instance argument has a value and sign appropriate to the parameter type.

What is the purpose of std :: Enable_if?

In C++ metaprogramming, std::enable_if is an important function to enable certain types for template specialization via some predicates known at the compile time. Using types that are not enabled by std::enable_if for template specialization will result in compile-time error.

Can a template be a template parameter?

Templates can be template parameters. In this case, they are called template parameters. The container adaptors std::stack, std::queue, and std::priority_queue use per default a std::deque to hold their arguments, but you can use a different container.


1 Answers

You can totally do what you want with enable_if, just remember, the substitution has to fail when the condition is false, so you must call type to ensure the substitution fails when specializing for various conditions.

#include <stdio.h>
#include <iostream>
#include <type_traits>

template <typename T, int DIM>
class foo
{
public:
    template <int D = DIM>
    typename std::enable_if<D == 1, T>::type
    function()
    {
        // do something
        return 1.0;
    }

    template <int D = DIM>
    typename std::enable_if<D == 2, T>::type
    function()
    {
        // do something else
        return 2342.0;
    }

};

int main(){
    foo<int, 1> object;
    int ak = object.function();
    std::cout << ak << "\n";

    return 0;
}

For simple scenarios, like the one above (where you check a specific value, rather than a range of values), you can also use partial specialization. But if you would like to specialize, say, for all values from 1-50, another for 51-200, and then a generic fallthrough, enable_if works great.

You can also use enable_if in the template signature. Just a quick example.

#include <stdio.h>
#include <iostream>
#include <type_traits>

template <typename T, int DIM>
class foo
{
public:
    template <int D = DIM, typename std::enable_if<D == 1, void>::type* = nullptr>
    T function()
    {
        // do something
        return 1.0;
    }

    template <int D = DIM, typename std::enable_if<D == 2, void>::type* = nullptr>
    T function()
    {
        // do something else
        return 2342.0;
    }

};

int main(){
    foo<int, 1> object;
    int ak = object.function();
    std::cout << ak << "\n";

    return 0;
}
like image 56
Alexander Huszagh Avatar answered Sep 20 '22 05:09

Alexander Huszagh