我有这段代码:
template<typename T1, typename T2>
auto operator*(const T1& a, const T2& b) -> decltype(viennacl::linalg::prod(a, b)) {
return viennacl::linalg::prod(a, b);
}
template<typename T1, typename T2>
auto operator*(const T1& a, const T2& b) -> decltype(prod(a, b)) {
return prod(a, b);
}
viennacl::linalg::prod
和prod
是两个不同的函数(也可能是模板化的)。
我认为如果某些模板函数定义不能用于某些类型,编译器会默默地忽略它并尝试另一个定义。这是错的吗?
Clang 3.3编译好,所有工作都按预期进行。然而,GCC 4.9引发了这个错误:
mathutils.hpp:77:6: error: redefinition of 'template<class T1, class T2> decltype (prod(a, b)) operator*(const T1&, const T2&)'
auto operator*(const T1& a, const T2& b) -> decltype(prod(a, b)) {
^
mathutils.hpp:72:6: note: 'template<class T1, class T2> decltype (viennacl::linalg::prod(a, b)) operator*(const T1&, const T2&)' previously declared here
auto operator*(const T1& a, const T2& b) -> decltype(viennacl::linalg::prod(a, b)) {
^
那么,哪个编译器错了?
可能的解决方法是什么? (如果不清楚我想做什么:我想实现operator*
,以便它使用viennacl::linalg::prod
或prod
,具体取决于哪一个提供了实现。)< / p>
小型独立测试用例:
namespace X {
template<typename T> struct Mat{};
template<typename T> struct MatExpr {};
template<typename T>
MatExpr<T> prod(Mat<T> const& A, Mat<T> const& B) { return MatExpr<T>(); }
};
struct Mat2 {};
template<typename T>
X::Mat<T> prod(X::Mat<T> const& A, Mat2 const& B) { return X::Mat<T>(); }
template<typename T1, typename T2>
auto operator*(const T1& a, const T2& b) -> decltype(X::prod(a, b)) {
return X::prod(a, b);
}
template<typename T1, typename T2>
auto operator*(const T1& a, const T2& b) -> decltype(prod(a, b)) {
return prod(a, b);
}
int main() {}
我报告说上游是GCC中的一个错误here。
答案 0 :(得分:0)
我确信有人会稍后再来,并在标准中引用gcc是对还是错的相关段落。与此同时,您可以尝试以下解决方法:
template<typename T1, typename T2>
auto operator *(const T1 &a,
const T2 &b) -> decltype(::prod<typename T1::value_type>(a, b))
我上面所做的是明确指定模板参数,以便它确切知道它应该实例化的prod
。另一个微妙之处在于我必须明确地对其进行全局限定,因此ADL不会妨碍它。如果没有这个,编译器会看到a
是namespace X
中的一个类型,并且它最终会同时考虑X::prod
和::prod
,这将是不明确的。
最后,对X::Mat
稍作修改,以便我们可以参考其类型T
:
namespace X
{
template<typename T> struct Mat { typedef T value_type; };
// ...