2

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

4

3 回答 3

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...}} {}
于 2015-03-04T04:47:26.550 回答
3

由于构造函数通过重载决议获胜,您可以提供所需构造函数的默认版本:

Point(Point&) = default;
Point(const Point&) = default;
Point(Point&&) = default;
Point& operator=(const Point&) = default;
于 2015-03-04T04:40:16.857 回答
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>or Point<int,3>or or Point<int,2>orPoint<user-define,numx>总是好的。


至少有三种解决方案供您选择。

首先,为了避免转发引用变量参数构造函数劫持了复制构造函数,所以去掉了这个函数,而不是

template<typename... Args>
        Point(Args... args) : std::array<T,N> {{args...}} {}//remove &&

这个解决方案是避免问题而不是解决问题。

其次,正如 TC 所说,停止转发引用变量参数构造函数劫持构造函数,只要当所有类型都适合时启用。这种方式比较复杂,也削弱了你模板的应用范围。

第三,正如 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);

没关系,但为什么呢?

正如 n4260 12.9 31.3 C++ Standrad 所说:

当尚未绑定到引用 (12.2) 的临时类对象将被复制/移动到具有相同 cv-unqualified 类型的类对象时,可以通过将临时对象直接构造到目标中来省略复制/移动操作省略的复制/移动

所以Point用三个浮点数直接调用构造函数,不调用复制构造函数。所以不调用转发引用变量参数构造函数传递一个点对象作为参数,这是你的编译错误。

缺点是每次使用该accumulate函数都需要传入的右值,并且不能是左值。

于 2015-03-06T09:15:41.507 回答