質問

I try to implement a functor version of static_cast for use in std::bind().

I am aware of Boost ll_static_cast<K>() (see using static_cast with boost::bind), but I am not using Boost right now.

There is a code example in Why do several of the standard operators not have standard functors? but it won't compile on GCC 4.2.1:

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

I managed to get something to compile, but I am not sure it's correct:

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

Can someone tell me if this version is correct, and if this is the case, why I need std::unary_function which is not used in the previous code example?

Usage:

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"));
役に立ちましたか?

解決

Given the lack of perfect forwarding in C++03, you'll have to make due with overloads:

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);
    }
};

Note that I'm explicitly making a typedef for result_type rather than inheriting from std::unary_function<>. The reason is that the first template parameter to std::unary_function<> is supposed to be operator()'s argument type, but because our operator() is a template we can't know this in advance, so it's disingenuous to supply one in the first place (especially void, which would imply that operator() is nullary, when in fact it is unary).


Also, for completeness' sake, here is the correct C++11 version of the functor:

template<class Target>
struct StaticCast
{
    template<class Source>
    Target operator ()(Source&& source) const
    {
        return static_cast<Target>(std::forward<Source>(source));
    }
}

他のヒント

One reason the first one doesn't work is probably because you are using rvalue references on a compiler that doesn't support C++11.

The reason you need std::unary_function is to enable std::result_of for your class which std::bind uses to deduce the result type, since there is no decltype in C++98.

If you look at std::unary_function you will see that it defines the type result_type from the template arguments you pass, which is in turned used by std::result_of or std::bind directly.

Well, generally your code is bad:

First, you may have troubles with temporary objects and r-values while requesting non-const reference for them

for example

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

won't even compile.

Then, you make a copy of object while casting. It may be do not that you want.

Source example free of that disadvantages due to move semantics

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top