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

すべての引数が暗黙的に に変換できる場合にのみオーバーロードの解決に参加するように、そのコンストラクターを制約する 1 つの方法を次に示します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 に答える
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>でもOK 。Point<int,3>_Point<int,2>Point<user-define,numx>


選択できるソリューションが少なくとも 3 つあります。

まず、転送参照変数パラメータコンストラクタを回避するために、コピーコンストラクタを乗っ取ったので、この関数を削除し、代わりに

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

この解決策は、問題を解決するのではなく、問題を回避することです。

2番目に、TCが言ったように、すべてのタイプが有効になっているときにすべてのタイプが適合する限り、参照変数パラメーターコンストラクターハイジャックされたコンストラクターの転送を停止します。この方法はより複雑ですが、テンプレートの適用範囲が狭くなります。

3 番目に、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 非修飾型のクラス オブジェクトにコピー/移動される場合、一時オブジェクトをターゲットに直接構築することにより、コピー/移動操作を省略できます。省略されたコピー/移動の

したがってPoint、3つのfloatを使用してコンストラクターを直接呼び出し、コピーコンストラクターを呼び出しません。したがって、転送参照変数パラメーターコンストラクターを呼び出して、ポイントオブジェクトをパラメーターとして渡すことはありません。これがコンパイルエラーの場所です。

欠点は、accumulate関数を使用するたびに着信右辺値が必要であり、左辺値にできないことです。

于 2015-03-06T09:15:41.507 に答える