Let's say, I have six types, and they each belong in a conceptual category.
Here is a diagram that shows this:
Or Perhaps a more specific example for you:
I want to write two functions that will handle all 6 types.
Types in "Category 1" get handled a certain way, and types in "Category 2" get handled a different way.
Let's get into the code. First, I'll create the six types.
//Category 1 Types
class Type_A{};
class Type_B{};
class Type_C{};
//Category 2 Types
class Type_D{};
class Type_E{};
class Type_F{};
Next, I'll create two type traits so that the category of the type can be discovered at compile time.
/* Build The Category 1 Type Trait */
//Type_A Type Trait
template <typename T>
struct Is_Type_A {
static const bool value = false;
};
template <>
struct Is_Type_A<Type_A> {
static const bool value = true;
};
//Type_B Type Trait
template <typename T>
struct Is_Type_B {
static const bool value = false;
};
template <>
struct Is_Type_B<Type_B> {
static const bool value = true;
};
//Type_C Type Trait
template <typename T>
struct Is_Type_C {
static const bool value = false;
};
template <>
struct Is_Type_C<Type_C> {
static const bool value = true;
};
//Category 1 Type Trait
template <typename T>
struct Is_Type_From_Category_1 {
static const bool value = Is_Type_A<T>::value || Is_Type_B<T>::value || Is_Type_C<T>::value;
};
/* Build The Category 2 Type Trait */
//Type_D Type Trait
template <typename T>
struct Is_Type_D {
static const bool value = false;
};
template <>
struct Is_Type_D<Type_D> {
static const bool value = true;
};
//Type_E Type Trait
template <typename T>
struct Is_Type_E {
static const bool value = false;
};
template <>
struct Is_Type_E<Type_E> {
static const bool value = true;
};
//Type_F Type Trait
template <typename T>
struct Is_Type_F {
static const bool value = false;
};
template <>
struct Is_Type_F<Type_F> {
static const bool value = true;
};
//Category 1 Type Trait
template <typename T>
struct Is_Type_From_Category_2 {
static const bool value = Is_Type_D<T>::value || Is_Type_E<T>::value || Is_Type_F<T>::value;
};
Now that I have two type traits to distinguish what category each of the six types fall into, I want to write two functions. One function will accept everything from Category 1, and the other function will accept everything from Category 2. Is there a way to do this without creating some kind of dispatching function? Can I find a way to have only two functions; one for each category?
EDIT: I have tried to use enable_if like this, but such an attempt will result in a compiler error.
//Handle all types from Category 1
template<class T ,class = typename std::enable_if<Is_Type_From_Category_1<T>::value>::type >
void function(T t){
//do category 1 stuff to the type
return;
}
//Handle all types from Category 2
template<class T ,class = typename std::enable_if<Is_Type_From_Category_2<T>::value>::type >
void function(T t){
//do category 2 stuff to the type
return;
}
Edit 2: I've tried the code provided in the link, but this isn't a yes or no decision on whether or not to call the function. It's which function do I call, given two type traits. This would be a redefinition error.
//Handle all types from Category 2
template<class T, class dummy = typename std::enable_if< Is_Type_From_Category_1<T>::value, void>::type>
void function(T t){
//do category 1 stuff to the type
return;
}
//Handle all types from Category 2
template<class T, class dummy = typename std::enable_if< Is_Type_From_Category_2<T>::value, void>::type>
void function(T t){
//do category 2 stuff to the type
return;
}
If any class has multiple functions with different parameters having the same name, they are said to be overloaded. If we have to perform a single operation with different numbers or types of arguments, we need to overload the function.
2) Member function declarations with the same name and the name parameter-type-list cannot be overloaded if any of them is a static member function declaration.
During compilation, the function signature is checked. So, functions can be overloaded, if the signatures are not the same. The return type of a function has no effect on function overloading, therefore the same function signature with different return type will not be overloaded.
Rust allows for a limited form of operator overloading. There are certain operators that are able to be overloaded. To support a particular operator between types, there's a specific trait that you can implement, which then overloads the operator.
Two functions signatures are not allowed to differ only by the default value of a template parameter. What would happen if you explicitly called function< int, void >
?
Usual usage of enable_if
is as the function return type.
//Handle all types from Category 1
template<class T >
typename std::enable_if<Is_Type_From_Category_1<T>::value>::type
function(T t){
//do category 1 stuff to the type
return;
}
//Handle all types from Category 2
template<class T >
typename std::enable_if<Is_Type_From_Category_2<T>::value>::type
function(T t){
//do category 2 stuff to the type
return;
}
I think using tag despatch would be easier than SFINAE.
template<class T>
struct Category;
template<>
struct Category<Type_A> : std::integral_constant<int, 1> {};
template<>
struct Category<Type_B> : std::integral_constant<int, 1> {};
template<>
struct Category<Type_C> : std::integral_constant<int, 1> {};
template<>
struct Category<Type_D> : std::integral_constant<int, 2> {};
template<>
struct Category<Type_E> : std::integral_constant<int, 2> {};
template<>
struct Category<Type_F> : std::integral_constant<int, 2> {};
template<class T>
void foo(std::integral_constant<int, 1>, T x)
{
// Category 1 types.
}
template<class T>
void foo(std::integral_constant<int, 2>, T x)
{
// Category 2 types.
}
template<class T>
void foo(T x)
{
foo(Category<T>(), x);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With