rxu - 1 year ago 108

C++ Question

How to specialize many template for all kinds of scalar values? (such as

`int`

`float`

`size_t`

`uint32_t`

`stdint`

Can I avoid specializing each template for each of the types?

I don't want to use boost or other non-standard libraries if possible.

There are some solutions at template specialization for a set of types:

- Replace each template with multiple functions. One function for each scalar type. (But there are many templates. That would mean writing many functions.)
- Fail if the template takes a non-scalar type. (But I also want to write template for array types. This would mean I need to change the names of the functions. One set of function names for scalar-scalar calculation. Another set for scalar-matrix calculation. Yet another set for matrix-matrix calculation. If I am trying to overload operators, i guess this won't work.)
- Metaprogramming solution by Nawaz. Same problem as in solution 2 for this case.
- Specialize a generic template for each scalar type. For example, write ,
`inline long getRatio<long>`

, etc. Can work, but need to do that for the many templates.`inline long getRatio<float>`

Thanks again.

Example:

`template <typename T>`

class SimpleArray{

public:

T* ar_data; //pointer to data

int size; //#elements in the array

SimpleArray(T* in_ar_data, int in_size){

ar_data = in_ar_data;

size = in_size;

};

template <typename T>

void operator+=(const SimpleArray<T>& B){

//array-array +=

int i;

for(i = 0; i < size; ++i){

ar_data[i] += B.ar_data[i];

}

}

/*

//The following doesn't work yet.

template <typename T>

void operator+=(const Scalar b){

//array-scalar +=

int i;

for(i = 0; i < size; ++i){

ar_data[i] += b

}

}

*/

};

int main(void){

int base_array[10];

SimpleArray<int> A(base_array, 10);

A += A;

}

Recommended for you: Get network issues from **WhatsUp Gold**. **Not end users.**

Answer Source

Condensing this down to a smaller example, based on the discussion in the comments on the question, you have a type `Matrix<T>`

and you wish to implement, say, `operator+=`

. The behaviour of this operator differs depending on whether the operand is a scalar or another matrix.

You therefore want to provide *two* specialisations; one for matrix-scalar operations, and one for matrix-matrix operations. Within those, you want to accept any valid scalar type, or any valid matrix type.

This is a classic use case for type traits and SFINAE using `std::enable_if`

. Define a trait `is_scalar`

:

```
// Base template:
template <typename T>
struct is_scalar : std::false_type {};
// Specialisations for supported scalar types:
template <> struct is_scalar<int> : std::true_type {};
template <> struct is_scalar<float> : std::true_type {};
template <> struct is_scalar<double> : std::true_type {};
// etc.
```

And a trait `is_matrix`

:

```
// Base template:
template <typename T>
struct is_matrix : std::false_type {};
// Specialisations:
template<typename T>
struct is_matrix<Matrix<T>> : std::true_type {};
// and possibly others...
```

Your operators will then be (member) function templates of the form:

```
template <typename T>
std::enable_if_t<is_scalar<T>::value, Matrix&> operator+=(const T& rhs) {
// Implementation for addition of scalar to matrix
}
template <typename T>
std::enable_if_t<is_matrix<T>::value, Matrix&> operator+=(const T& rhs) {
// Implementation for addition of matrix to matrix
}
```

Note that `is_scalar`

is already provided for you by the standard library! All this leaves is for you to define `is_matrix`

specialisations for any matrix types you support.

Recommended from our users: **Dynamic Network Monitoring from WhatsUp Gold from IPSwitch**. ** Free Download**