Home > OS >  Specialization of function template without changing its prototype
Specialization of function template without changing its prototype

Time:11-04

Suppose A is some class and I have the following function template with a nontype argument:

template <typename T, int v> void func(const T& x);

Now I wish to have different implementations for different types T e.g. I want to have a general version of func for general types (general means types that do not have a special version of func designed for it) and a special version of func for class A which is different from the general version. Also, the users of this design call func in the following way:

func<int,9>(11);
func<A,1>(a); //a is an object of class A

My question is, given that function templates are not allowed to be partially specialized and overloading func would not allow users to call it in the way of func<A,1>, how am I able to correctly implement func?

CodePudding user response:

Just let the type system do the work for you:

#include <iostream>

class A {};

// Default implementation
template <typename T, int v> void func(const T& x)
{
    std::cout << x   v << "\n";
}

// Specialized for A
template <typename T, int v> void func(const A& x) //<-- matches A for argument T
{
    std::cout << "Groovy " << v << "\n";
}

int main()
{
    func<int, 9>(11);
    func<double, 3>(0.14159);
    func<const char*, 3>("uh oh!");
    func<A, 1>(A());
}

Output:

20
3.14159
oh!
Groovy 1

Live example here

CodePudding user response:

You can use C 20 concepts to do this:

#include <concepts>

struct A {};

template <typename T, int v> 
void func(const T& x) {
  // general version
}

template <std::same_as<A> T, int v>
void func(const T& x) {
   // special version
}

Demo.

CodePudding user response:

If you just want to handle A and doesn't need a customization point, since C 17, you might use if conxtexpr:

template <typename T, int v>
void func(const T& x)
{
    if constexpr (std::is_same_v<T, A>) {
        // specific code for A
    } else {
        // generic code: Not a A
    }
}

Else, you may delegate implementation to other functors/functions that you can customize:

template <typename T, int v>
struct func_impl
{
    void operator()(const T&) const { /* Generic code */ }
};

template <typename T, int v> void func(const T& x)
{
    func_impl<T, v>{}(x);
}

// Customization part
class A;

template <int v>
struct func_impl<A, v>
{
    void operator()(const A&) const { /* Specific code for A */ }
};

or

// Allow both parameters to be deducible, to ease the possibility to overload
// on any part.
template <typename T, int v>
void func_impl(std::integral_constant<int, v>, const T& x)
{
    // Generic code
}

template <typename T, int v> void func(const T& x)
{
    func_impl(std::integral_constant<int, v>{}, x);
}

// Customization point (with ADL)
class A;

template <int v>
void func_impl(std::integral_constant<int, v>, const A& x)
{
    // Specific code for A.
}

CodePudding user response:

You can use std::enable_if to do what you want as follows:

#include <iostream>

class A 
{
};

template <typename T, int v> void func(const T&) //primary template
{
    std::cout<<"primary template"<<std::endl;
}

template <typename T,int v, typename std::enable_if<std::is_same<T, A>::value, int>::type = 0>
void func(const A&)
{
    std::cout<<"choosen for A"<<std::endl;
}
int main()
{   
    A a;
    func<int, 9>(11);
    func<A, 9>(a);
    
}

Thanks to @Jarod42 for correcting me.(see the comments below and edit history of this post)

  • Related