I am having trouble getting my code to compile. clang, g++ and icpc all give different error messages,
A bit of background before getting to the question itself:
I am working now on a template class hierarchy for working with Matrices. There are template parameters for the data type (either float or double) and for "Implementation Policy" -- at present this includes regular C++ code with loops and Intel MKL versions. The following is an abridged summary (please disregard lack of forward references, etc. in this -- that is unrelated to my question):
// Matrix.h
template <typename Type, typename IP>
class Matrix : public Matrix_Base<Type, IP>;
template <typename Matrix_Type>
class Matrix_Base{
/* ... */
// Matrix / Scalar addition
template <typename T>
Matrix_Base& operator+=(const T value_) {
return Implementation<IP>::Plus_Equal(
static_cast<Matrix_Type&>(*this), value_);
/* More operators and rest of code... */
};
struct CPP;
struct MKL;
template <typename IP>
struct Implementation{
/* This struct contains static methods that do the actual operations */
The trouble that I'm having right now is related to the implementation of the Implementation class (no pun intended). I know that I can use specialization of the Implementation template class to specialize template <> struct Implementation<MKL>{/* ... */};
however, this will result in a lot of code duplication as there are a number of operators (such as matrix-scalar addition, subtraction, ... ) for which both the generic and the specialized versions use the same code.
So, instead, I thought that I could get rid of the template specialization and just use enable_if to provide different implementations for those operators which have different implementations when using MKL (or CUDA, etc.).
This has proven to me to be more challenging than I had originally expected. The first -- for operator += (T value_)
works fine. I added in a check just to make sure that the parameter is reasonable (this can be eliminated if it is the source of my troubles, which I doubt).
template <class Matrix_Type, typename Type, typename enable_if<
std::is_arithmetic<Type>::value >::type* dummy = nullptr>
static Matrix_Type& Plus_Equal(Matrix_Type& matrix_, Type value_){
uint64_t total_elements = matrix_.actual_dims.first * matrix_.actual_dims.second;
//y := A + b
#pragma parallel
for (uint64_t i = 0; i < total_elements; ++i)
matrix_.Data[i] += value_;
return matrix_;
}
However, I am having a really hard time figuring out how to deal with operator *=(T value_)
. This is due to the fact that float
and double
have different implementations for MKL but not in the general case.
Here is the declaration. Note that the 3rd parameter is a dummy parameter and was my attempt at forcing function overloading, since I cannot use partial template function specialization:
template <class Matrix_Type, typename U, typename Type =
typename internal::Type_Traits< Matrix_Type>::type, typename enable_if<
std::is_arithmetic<Type>::value >::type* dummy = nullptr>
static Matrix_Type& Times_Equal(Matrix_Type& matrix_, U value_, Type dummy_ = 0.0);
Definition for general case. :
template<class IP>
template <class Matrix_Type, typename U, typename Type, typename enable_if<
std::is_arithmetic<Type>::value >::type* dummy>
Matrix_Type& Implementation<IP>::Times_Equal(Matrix_Type& matrix_, U value_, Type){
uint64_t total_elements = matrix_.actual_dims.first * matrix_.actual_dims.second;
//y := A - b
#pragma parallel
for (uint64_t i = 0; i < total_elements; ++i)
matrix_.Data[i] *= value_;
return matrix_;
}
The trouble starts when I try to implement a specialization for MKL:
template<>
template <class Matrix_Type, typename U, typename Type, typename enable_if<
std::is_arithmetic<Type>::value >::type* dummy>
Matrix_Type& Implementation<implementation::MKL>::Times_Equal(
Matrix_Type& matrix_,
U value_,
typename enable_if<std::is_same<Type,float>::value,Type>::type)
{
float value = value_;
MKL_INT total_elements = matrix_.actual_dims.first * matrix_.actual_dims.second;
MKL_INT const_one = 1;
//y := a * b
sscal(&total_elements, &value, matrix_.Data, &const_one);
return matrix_;
}
This gives me an error in clang:
_error: out-of-line definition of 'Times_Equal' does not match any declaration in 'Implementation'_
and in g++ (shortened somewhat)
_error: template-id `Times_Equal<>' for 'Matrix_Type& Implementation::Times_Equal(...)' does not match any template declaration.
The code compiles perfectly fine if I change the 3rd parameter to be Type, rather than having the enable_if. But when I do that, I cannot see how to have separate implementations for float and double.
Any help would be greatly appreciated.