【发布时间】:2014-01-06 23:42:52
【问题描述】:
我无法编译我的代码。 clang、g++ 和 icpc 都会给出不同的错误信息,
在进入问题本身之前先了解一下背景:
我现在正在研究用于处理矩阵的模板类层次结构。数据类型(浮点型或双精度型)和“实施策略”有模板参数——目前这包括带有循环和英特尔 MKL 版本的常规 C++ 代码。以下是一个简短的摘要(请忽略此处缺少前向引用等 - 这与我的问题无关):
// 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 */
我现在遇到的麻烦与实现类的实现有关(没有双关语)。我知道我可以使用实现模板类的特化来特化template <> struct Implementation<MKL>{/* ... */}; 但是,这将导致大量代码重复,因为有许多运算符(例如矩阵标量加法,减法,...)通用版和专用版都使用相同的代码。
所以,相反,我认为我可以摆脱模板专业化,只使用 enable_if 为那些在使用 MKL(或 CUDA 等)时具有不同实现的运算符提供不同的实现。
事实证明,这比我最初预期的更具挑战性。第一个 - operator += (T value_) 工作正常。我添加了一个检查只是为了确保参数是合理的(如果它是我的麻烦的根源,这可以消除,我怀疑)。
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_;
}
但是,我很难弄清楚如何处理operator *=(T value_)。这是因为 float 和 double 对 MKL 有不同的实现,但不是在一般情况下。
这是声明。请注意,第三个参数是一个虚拟参数,是我尝试强制函数重载,因为我不能使用部分模板函数特化:
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);
一般情况的定义。 :
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_;
}
当我尝试实现 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_;
}
这给了我一个clang错误:
_错误:“Times_Equal”的外线定义与“实施”中的任何声明都不匹配_
在 g++ 中(稍微缩短)
_错误: 'Matrix_Type& Implementation::Times_Equal(...)' 的模板 ID `Times_Equal' 与任何模板声明都不匹配。
如果我将第三个参数更改为 Type,而不是启用 enable_if,则代码编译得非常好。但是当我这样做时,我看不到如何为 float 和 double 分别实现。
任何帮助将不胜感激。
【问题讨论】:
-
typename enable_if< std::is_arithmetic<Type>::value >::type* dummy = nullptr也可以实现为typename = enable_if< std::is_arithmetic<Type>::value >::type,它有点短;) -
“请注意,第三个参数是一个虚拟参数,是我尝试强制函数重载的尝试”对于(正常)重载解析,使用默认参数的参数将被忽略。 (它们可能仍会在函数模板 IIRC 的部分排序中发挥作用。)
-
@DyP,你的第二点很好;但是,我的理解是,如果 Type 不等于 'float',那么最终参数将导致替换失败,并且将排除实现。显然,我错了,因为它不会编译;但是,我真的不明白我在这里做错了什么。请注意,如果没有默认参数,我的一般案例实现会遇到麻烦。我想我总是可以将其他参数传递给实现,但我宁愿不这样做。而且我更多宁愿让编译器推导出模板参数。
-
您遇到编译器错误,提示您定义的方法与类定义中的任何声明都不匹配。也许你应该声明你正在定义的重载?
-
老实说,我会使用更少的
enable_if和更多的标签调度。我会做一个RootImplementation<Derived>,它使用CRTP 发送回你的Implmentation<X>,这是专门基于MKL 与标准的。 SFINAE,但通常是一个糟糕的设计决策。
标签: c++ templates c++11 template-specialization partial-specialization