在没有 SFINAE 的情况下启用 class 方法

Enable class methods without SFINAE

我正在寻找一种在没有 SFINAE 的情况下启用 class 方法 的方法,可能是通过继承。

Im working on an improved version of std::function(函子class with operator())哪个限定符(const,volatile)取决于它的模板参数,例如:

  • myfunctor<void()> 提供 operator() ()
  • myfunctor<void() const> 提供 operator() () const
  • myfunctor<void() volatile> 提供 operator() () volatile

等等。

我不能使用 SFINAE 解决这个问题的主要原因是,如果我使用 SFINAE,operator() 需要像这样被模板化:

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

这意味着 operator() 不再可通过使用引用:

&my_functor<void() const>::operator()

我的第一个意图是使用 superclasses,我可以从中继承 operator() 方法,但这些方法仍然需要访问包含在 [=22 中的主要实现=] 它包含一个虚拟 class,我不想将 std::unique_ptr 的引用传递给超级 class。

是否有另一种或更好的方法来启用 class 方法而不对其进行模板化(不包括 SFINAE)。

operator() isn't referenceable anymore (...)

使用基于 SFINAE 的方法,运算符仍然可用,语法为:

&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

您可以使用 CRTP 习惯用法,这样 impl 可以通过向下转换访问 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();    
};

DEMO