Reputation: 1573
I'm looking for a way to enable class methods without SFINAE, maybe through inheritance.
Im working on an improved version of std::function (functor class with operator()
) which qualifier (const, volatile) is dependent on it's template argument for example:
myfunctor<void()>
provides operator() ()
myfunctor<void() const>
provides operator() () const
myfunctor<void() volatile>
provides operator() () volatile
and so on.
The main reason why i can't use SFINAE to solve this is that if i use SFINAE the operator() needs to be templated like:
template<typename R = ReturnType>
auto operator() (Args&&... args)
-> std::enable_if_t<!Constant && !Volatile, R>
{
return (*_impl)(std::forward<Args>(args)...);
}
template<typename R = ReturnType>
auto operator() (Args&&... args) const volatile
-> std::enable_if_t<Constant && Volatile, R>
{
return (*_impl)(std::forward<Args>(args)...);
}
which means the operator()
isn't referenceable anymore through using:
&my_functor<void() const>::operator()
My first intention was to use superclasses where i can inherit the operator()
methods from but the methods still need to have access to the main implementation which is contained by a std::unique_ptr
which holds a virtual class, and i don't want to pass a reference of the std::unique_ptr
to the superclass.
Is there another or better way to enable class methods without templating it (which excludes SFINAE).
Upvotes: 4
Views: 211
Reputation: 48487
operator() isn't referenceable anymore (...)
With the SFINAE-based approach the operator is still accessible, with syntax:
&my::functor<void() const>::operator()<>
// ↑↑
My first intention was to use superclasses where i can inherit the operator() methods from but the methods still need to have access to the main implementation which is contained by a std::unique_ptr
You can use the CRTP idiom, so that impl
is accessible by down-casting this
:
template <typename /*Fn*/, bool /*NonCopyable*/, bool /*Constant*/, bool /*Volatile*/>
class function;
template <typename CRTP>
struct call_operator;
template <typename ReturnType, typename... Args, bool NonCopyable>
struct call_operator<function<ReturnType(Args...), NonCopyable, true, false>>
{
using func = function<ReturnType(Args...), NonCopyable, true, false>;
ReturnType operator()(Args&&... args) const
{
return (*static_cast<const func*>(this)->_impl)(std::forward<Args>(args)...);
}
};
template <typename ReturnType, typename... Args, bool NonCopyable>
struct call_operator<function<ReturnType(Args...), NonCopyable, true, true>>
{
using func = function<ReturnType(Args...), NonCopyable, true, true>;
ReturnType operator()(Args&&... args) const volatile
{
return (*static_cast<const volatile func*>(this)->_impl)(std::forward<Args>(args)...);
}
};
template<typename ReturnType, typename... Args, bool NonCopyable, bool Constant, bool Volatile>
class function<ReturnType(Args...), NonCopyable, Constant, Volatile> : call_operator<function<ReturnType(Args...), NonCopyable, Constant, Volatile>>
{
friend struct call_operator<function<ReturnType(Args...), NonCopyable, Constant, Volatile>>;
std::unique_ptr<wrapper_impl<ReturnType(Args...)>> _impl;
public:
function()
: _impl(new fake_wrapper_impl<ReturnType(Args...)>()) { }
using call_operator<function<ReturnType(Args...), NonCopyable, Constant, Volatile>>::operator();
};
Upvotes: 4