std :: accumulate中的转换无效

时间:2015-03-04 04:19:19

标签: c++ c++11 accumulate stdarray

我有一个类代表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实现与我的构造函数不兼容的问题吗?

3 个答案:

答案 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函数时都需要传入的右值,而且不能是左值。