Функторная версия static_cast в std :: bind () - PullRequest
1 голос
/ 10 января 2012

Я пытаюсь реализовать функторную версию static_cast для использования в std::bind().

Мне известно о Boost ll_static_cast<K>() (см. с использованием static_cast с boost :: bind ), но сейчас я не использую Boost.

В * 1010 есть пример кода. Почему некоторые стандартные операторы не имеют стандартных функторов? , но он не будет компилироваться в GCC 4.2.1:

template <typename Target>
struct StaticCast
{
    template <typename Source>
    Target operator()(Source&& source) const
    {
        return static_cast<Target>(source);
    }
}

Мне удалось что-то скомпилировать, но я не уверен, что это правильно:

template <class Target>
struct StaticCast : public std::unary_function<void, Target> {
    template <class Source>
    Target operator()(Source& src) const {
        return static_cast<Target>(src);
    }
};

Может кто-нибудь сказать мне, верна ли эта версия, и если это так, зачем мне нужен std::unary_function, который не используется в предыдущем примере кода?

Использование:

std::vector<BaseObject*> vec;  // BaseObject* are known to be of type 
    // DerivedObject* of course, please don't ask me how or why...

std::for_each(vec.begin(), vec.end(),
    std::bind(&DerivedObject::doStuff,
        std::bind(StaticCast<DerivedObject*>(), std::placeholders::_1),
    "with some string"));

Ответы [ 3 ]

0 голосов
/ 10 января 2012

Ну, в общем, ваш код плохой:

Во-первых, у вас могут возникнуть проблемы с временными объектами и значениями r при запросе неконстантной ссылки на них

например

float f = StaticCast<float>()(4);

даже не скомпилируется.

Затем вы делаете копию объекта во время приведения. Это может быть не то, что вы хотите.

Исходный пример без этих недостатков из-за move семантики

0 голосов
/ 10 января 2012

Учитывая отсутствие идеальной пересылки в C ++ 03, вам придется сделать это из-за перегрузок:

template<class Target>
struct StaticCast
{
    typedef Target result_type;

    template<class Source>
    Target operator ()(Source& src) const
    {
        return static_cast<Target>(src);
    }

    template<class Source>
    Target operator ()(Source const& src) const
    {
        return static_cast<Target>(src);
    }
};

Обратите внимание, что я явно делаю typedef для result_typeчем наследование от std::unary_function<>.Причина в том, что первый параметр шаблона для std::unary_function<> должен быть типом аргумента operator(), но поскольку наш operator() является шаблоном, мы не можем знать это заранее, поэтому нечестно указывать его впервое место (особенно void, что подразумевает, что operator() является нулевым, тогда как на самом деле он является унарным).


Кроме того, для полноты, здесь правильный C ++ 11версия функтора:

template<class Target>
struct StaticCast
{
    template<class Source>
    Target operator ()(Source&& source) const
    {
        return static_cast<Target>(std::forward<Source>(source));
    }
}
0 голосов
/ 10 января 2012

Одна из причин, по которой первая не работает, возможно, заключается в том, что вы используете ссылки на rvalue в компиляторе, который не поддерживает C ++ 11.

Причина, по которой вам нужно std::unary_function, состоит в том, чтобы включить std::result_of для вашего класса, который std::bind использует для вывода типа результата, поскольку в C ++ 98 нет decltype.

Если вы посмотрите на std::unary_function, то увидите, что он определяет тип result_type из передаваемых вами аргументов шаблона, который в свою очередь используется std::result_of или std::bind напрямую.

...