派生 class 的重载解析失败
overload resolution fails for derived class
我正在使用 class mArray,它实现了具有可变维度的数值数据容器
template <typename T>
class mArray<T>: {
...
std::vector<T> my_data;
}
另一个 class mImage
继承自 mArray
并提供图像特定的操作,另一个 class mDcmImage
继承自 mImage
和提供特定于格式的功能。
我认为这是一种分离不同类型功能的非常简洁的方法。
一个示例或 mArray
功能:逐元素加法:
// add a mArray to the data [1]
template <typename U>
void operator+= (const mArray<U>& other) {
if (other.getSizes() != getSizes())
throw std::invalid_argument {"incompatible sizes"};
else {
std::transform (my_data.begin(),
my_data.end(),
my_data.begin(),
my_data.begin(),
[]( const T &a, const U &b) { return a+b; } );
}
return;
}
// add an element to the data [2]
template <typename U>
void operator+= (const U& rhs) {
assert (!std::is_arithmetic<U>::value);
std::transform (my_data.begin(),
my_data.end(),
my_data.begin(),
[&rhs]( const T &lhs) { return lhs+rhs; } );
return;
}
(getSizes()
是一个 mArray
函数)
但是现在我的代码从文件中加载 mDcmImage<int>
,当我使用
typedef int intensity;
mDcmImage<intensity> im1 ("/tmp/test1.im");
mDcmImage<intensity> im2 ("/tmp/test2.im");
im1 += im2;
然后我得到以下错误:
mArray.hpp required from ‘struct mArray<T>::operator+=(const U&)
[with U = mDcmImage<int>; T = int]::<lambda(const int&)>’|
mArray.hpp required from ‘void mArray<T>::operator+=(const U&)
[with U = mDcmImage<int>; T = int]’|
test.cpp required from here|
mArray.hpp error: no match for ‘operator+’ in ‘lhs + rhs’|
换句话说:虽然我编写了另一个 mArray
的加法以及一个值的加法,但是当我在主程序中调用 +=
运算符将两个数组加在一起时,它对单个值使用 +=
实现。
我试过好几种,比如
- 对
operator+=
的值版本使用 std::enable_if<std::is_arithmetic<U>::value >::type*
-- 不允许,因为 operator+=
严格采用 1 个参数
- 同时为
mImage
和 mDcmImage
定义了 operator+=
的两个版本——在这些级别上它也使用了错误的实现。
在 中选择了 运算符的正确版本 -- 为什么现在不选择?我不明白为什么重载决议在这里失败了。
模板参数推导后,第二个版本完美匹配:
template <typename U> void operator+= (const U& rhs); // U = mDcmImage<int>
与需要从 mDcmImage
转换为 mArray
的第一个版本相比:
template <typename U> void operator+= (const mArray<U>& other); // U = int
所以它是通过重载决议选择的。
最简单的修复可能是修改单值版本以仅采用 T
并依赖隐式转换:
void operator+= (const T& rhs);
SFINAE 也是可以的,例如在 return 类型中:
template <typename U>
typename std::enable_if<std::is_arithmetic<U>::value>::type operator+= (const U& rhs);
namespace details {
template<template<class...>class Z>
std::false_type inherits_from_template_helper(...);
template<template<class...>class Z, class...Us>
std::true_type inherits_from_template_helper(Z<Us...>&&);
}
// C++14 has this in `std`:
template<class T>using decay_t=typename std::decay<T>::type;
template<template<class...>class Z, class T>
using inherits_from_template
= decltype(
details::inherits_from_template_helper<Z>(
std::declval<decay_t<T>>()
)
);
template<class T>
using is_mArray = inherits_from_template<mArray, T>;
是一个特征测试,表示“传入的类型基本上是 mArray
现在使用 SFINAE 或标签分派来分派以更正 +=,具体取决于您的参数是否为 mArray
。
template<class U>
mArray<T>& operator+=(U&& u) {
increase_by( std::forward<U>(u), is_mArray<U>{} );
return *this;
}
template<class U>
void increase_by( U const& u, std::false_type /* is_mArray<U> */ ) {
// scalar addition code
}
template<class U>
void increase_by( mArray<U> const& u, std::true_type /* is_mArray<U> */ ) {
// mArray addition code
}
我正在使用 class mArray,它实现了具有可变维度的数值数据容器
template <typename T>
class mArray<T>: {
...
std::vector<T> my_data;
}
另一个 class mImage
继承自 mArray
并提供图像特定的操作,另一个 class mDcmImage
继承自 mImage
和提供特定于格式的功能。
我认为这是一种分离不同类型功能的非常简洁的方法。
一个示例或 mArray
功能:逐元素加法:
// add a mArray to the data [1]
template <typename U>
void operator+= (const mArray<U>& other) {
if (other.getSizes() != getSizes())
throw std::invalid_argument {"incompatible sizes"};
else {
std::transform (my_data.begin(),
my_data.end(),
my_data.begin(),
my_data.begin(),
[]( const T &a, const U &b) { return a+b; } );
}
return;
}
// add an element to the data [2]
template <typename U>
void operator+= (const U& rhs) {
assert (!std::is_arithmetic<U>::value);
std::transform (my_data.begin(),
my_data.end(),
my_data.begin(),
[&rhs]( const T &lhs) { return lhs+rhs; } );
return;
}
(getSizes()
是一个 mArray
函数)
但是现在我的代码从文件中加载 mDcmImage<int>
,当我使用
typedef int intensity;
mDcmImage<intensity> im1 ("/tmp/test1.im");
mDcmImage<intensity> im2 ("/tmp/test2.im");
im1 += im2;
然后我得到以下错误:
mArray.hpp required from ‘struct mArray<T>::operator+=(const U&)
[with U = mDcmImage<int>; T = int]::<lambda(const int&)>’|
mArray.hpp required from ‘void mArray<T>::operator+=(const U&)
[with U = mDcmImage<int>; T = int]’|
test.cpp required from here|
mArray.hpp error: no match for ‘operator+’ in ‘lhs + rhs’|
换句话说:虽然我编写了另一个 mArray
的加法以及一个值的加法,但是当我在主程序中调用 +=
运算符将两个数组加在一起时,它对单个值使用 +=
实现。
我试过好几种,比如
- 对
operator+=
的值版本使用std::enable_if<std::is_arithmetic<U>::value >::type*
-- 不允许,因为operator+=
严格采用 1 个参数 - 同时为
mImage
和mDcmImage
定义了operator+=
的两个版本——在这些级别上它也使用了错误的实现。
在
模板参数推导后,第二个版本完美匹配:
template <typename U> void operator+= (const U& rhs); // U = mDcmImage<int>
与需要从 mDcmImage
转换为 mArray
的第一个版本相比:
template <typename U> void operator+= (const mArray<U>& other); // U = int
所以它是通过重载决议选择的。
最简单的修复可能是修改单值版本以仅采用 T
并依赖隐式转换:
void operator+= (const T& rhs);
SFINAE 也是可以的,例如在 return 类型中:
template <typename U>
typename std::enable_if<std::is_arithmetic<U>::value>::type operator+= (const U& rhs);
namespace details {
template<template<class...>class Z>
std::false_type inherits_from_template_helper(...);
template<template<class...>class Z, class...Us>
std::true_type inherits_from_template_helper(Z<Us...>&&);
}
// C++14 has this in `std`:
template<class T>using decay_t=typename std::decay<T>::type;
template<template<class...>class Z, class T>
using inherits_from_template
= decltype(
details::inherits_from_template_helper<Z>(
std::declval<decay_t<T>>()
)
);
template<class T>
using is_mArray = inherits_from_template<mArray, T>;
是一个特征测试,表示“传入的类型基本上是 mArray
现在使用 SFINAE 或标签分派来分派以更正 +=,具体取决于您的参数是否为 mArray
。
template<class U>
mArray<T>& operator+=(U&& u) {
increase_by( std::forward<U>(u), is_mArray<U>{} );
return *this;
}
template<class U>
void increase_by( U const& u, std::false_type /* is_mArray<U> */ ) {
// scalar addition code
}
template<class U>
void increase_by( mArray<U> const& u, std::true_type /* is_mArray<U> */ ) {
// mArray addition code
}