Как правильно пересылать / переносить static_cast? - PullRequest
0 голосов
/ 04 сентября 2018

Как правило, мне нужна оболочка функции static_cast для использования в качестве предиката (для преобразования), так как static_cast напрямую не может использоваться таким образом. На этот раз лямбда не является предпочтительной. Моя реализация:

template<typename T> 
struct static_cast_forward{
  template<class U>
  T operator()(U&& u) const {
    return static_cast<T>(std::forward<U>(u));
  }
};

Во-первых, хотя у меня есть фундаментальное понимание ссылок на rvalue и т. Д. Я хочу проверить, является ли это правильным способом реализации этого forward / wrapper?

Во-вторых, спросить, если какая-либо библиотека std или boost уже обеспечивает эту функцию?

Дополнительно: вы бы отправили другие приведения таким же образом?

ФАКТИЧЕСКИЙ СЛУЧАЙ:

Мой фактический случай - использовать с boost::range, что-то вроде:

//auto targetsRange = mixedRange | boost::adaptors::filtered(TYPECHECK_PRED) | boost::adaptors::transformed(static_cast_forward<TARGET_PTR_TYPE>());

ПРИМЕРЫ РАБОТЫ:

#include <algorithm>
template<typename T>
struct static_cast_forward {
    template<class U>
    T operator()(U&& u) const {
        return static_cast<T>(std::forward<U>(u));
    }
};

//example 1:

void test1() {
    std::vector<double> doubleVec{1.1, 1.2};
    std::vector<int> intVec;
    std::copy(doubleVec.begin(), doubleVec.end(), intVec.end());//not ok (compiles, but gives warning) 
    std::transform(doubleVec.begin(), doubleVec.end(), std::back_inserter(intVec), static_cast_forward<int>()); //ok
}

//example 2:

struct A {
    virtual ~A() {} 
};

struct B : public A {
};

struct C : public A {
};

void test2() {
    std::vector<A*> vecOfA{ new B, new B};
    std::vector<B*> vecOfB;
    //std::transform(vecOfA.begin(), vecOfA.end(), std::back_inserter(vecOfB), static_cast<B*>); //not ok: syntax error..
    std::transform(vecOfA.begin(), vecOfA.end(), std::back_inserter(vecOfB), static_cast_forward<B*>() ); //ok
}

1 Ответ

0 голосов
/ 04 сентября 2018

Дополнение после уточнения вопроса.

В обоих случаях вам не нужно ничего делать std::forward, потому что нечего двигаться, вам нужен только актерский состав. Но если вы хотите обобщить и на подвижные типы, то ваша реализация мне подходит. Только не называйте это forward, потому что это не forward. Насколько я знаю, в std нет ничего похожего на ваше struct.

Так что я бы просто добавил test3(), который действительно нуждается в перемещении:

struct B { };

struct D { 
    explicit D(B&&) { }   // Note: explicit!
};

void test3()
{
    std::vector<B> vb{B{}, B{}};
    std::vector<D> vd;

    // Won't compile because constructor is explicit
    //std::copy(std::make_move_iterator(vb.begin()), std::make_move_iterator(vb.end()), std::back_inserter(vd));

    // Works fine
    std::transform(std::make_move_iterator(vb.begin()), std::make_move_iterator(vb.end()), std::back_inserter(vd), static_cast_forward<D>());
}

Ответ до выяснения вопроса.

Если я правильно понял ваше намерение, то это то, что вы хотите:

template<typename T>
struct static_cast_forward {
    template<class U>
    decltype(auto) operator()(U&& u) const
    {
        if constexpr (std::is_lvalue_reference_v<U>)
            return static_cast<T&>(u);
        else
            return static_cast<T&&>(u);
    }
};

Тогда у вас есть:

struct B { };
struct D : B { };

void foo() {
    D d;
    static_cast_forward<B> scf_as_B;

    static_assert(std::is_same_v<decltype(scf_as_B(D{})), B&&>);
    static_assert(std::is_same_v<decltype(scf_as_B(d)), B&>);
}
...