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
}
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)