我有一个类代表N
维度中具有min
静态函数的点(按字段最小字段)
template<typename T, std::size_t N>
class Point : public std::array<T,N>
{
public:
template<typename... Args>
Point(Args&&... args) : std::array<T,N>{{args...}} {}
// ...
static Point min(const Point&, const Point&) {
// ...
}
};
写作时,一切都很顺利
Point<float,3> a = {0.f, 1.f, 2.f};
Point<float,3> b = {2.f, 1.f, 0.f};
Point<float,3> c = Point<float,3>::min(a,b); // OK
但是如果我尝试在数组上使用std::accumulate
Point<float,3> array[100] = ... ;
Point<float,3> min = std::accumulate(array, array+100, array[0], Point<float,3>::min); // Error
我收到错误:
error: cannot convert ‘Point<float, 3ul>’ to ‘float’ in initialization
adimx::Point<T,N>::Point(Args&&... args) : std::array<T,N>{{args...}}
这是std::accumulate
实现与我的构造函数不兼容的问题吗?
答案 0 :(得分:4)
这是约束该构造函数的一种方法,只有当所有参数都可以隐式转换为float
时才会参与重载解析:
template<bool... > class bool_pack;
template<bool... b>
using all_true = std::is_same<bool_pack<true, b...>, bool_pack<b..., true>>;
template<typename... Args,
class = typename std::enable_if<all_true<std::is_convertible<Args, float>::value...>::value>::type>
Point(Args&&... args) : std::array<T,N>{{args...}} {}
答案 1 :(得分:3)
由于构造函数通过重载决策获胜,因此您可以提供所需构造函数的默认版本:
Point(Point&) = default;
Point(const Point&) = default;
Point(Point&&) = default;
Point& operator=(const Point&) = default;
答案 2 :(得分:0)
template <bool J>
using disable_if=enable_if<!J>;
template <typename T,typename... Tail> struct getHead
{
typedef typename decay<T>::type type;
};
template<typename... Args,typename = typename disable_if<is_same<typename getHead<Args...>::type,Point<T,N> >::value >::type >
Point(Args&&... args) : std::array<T,N> {{args...}}
{
//...
}
我相信这个解决方案是完美的。我们只在参数是Point本身时停止转发引用变量参数构造函数。其他任何类型仍然调用转发引用变量参数构造函数。
无论Point<float,3>
或Point<int,3>
或Point<int,2>
还是Point<user-define,numx>
,都可以。
至少有三种解决方案供您选择。
首先,为了避免转发引用变量参数构造函数劫持了复制构造函数,所以删除了这个函数,而不是
template<typename... Args>
Point(Args... args) : std::array<T,N> {{args...}} {}//remove &&
这个解决方案是避免问题而不是解决问题。
第二,正如TC所说,停止转发引用变量参数构造函数hijacked构造函数,只要所有类型都适合启用时。这种方式更复杂,但也会削弱模板的应用范围。
第三次,正如MSalters所说,将array[0]
更改为Point<float,3>(0,0,0)
,
Point<float,3> min = std::accumulate(array, array+100, Point<float,3>(0,0,0), Point<float,3>::min);
没关系,但为什么?
as n4260 12.9 31.3 C ++ Standrad说:
当一个临时类对象尚未绑定到引用时 (12.2)将被复制/移动到具有相同的类对象 cv-unqualified类型,可以省略复制/移动操作 将临时对象直接构造到目标中 省略了复制/移动
因此,直接使用三个float调用Point
构造函数,不调用复制构造函数。所以不调用转发引用变量参数构造函数将Point Object作为参数传递,这是编译错误的地方。
缺点是,每次使用accumulate
函数时都需要传入的右值,而且不能是左值。