Functor version of static_cast in std::bind()
-
15-04-2021 - |
質問
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