繁体   English   中英

模板和重载决议

[英]templates and overload resolution

我正在阅读“C ++模板,完整指南”一书,第22章介绍了类型擦除的概念,以及std :: function-linke类的示例:

#include "functorwrapper.hpp"

// primary template (declaration)
template <typename Signature>
class Function;

// partial class template specialization
template <typename ReturnType, typename... Args>
class Function<ReturnType(Args...)>
{
public:
    // constructors
    Function() : mFunctorWrapper(nullptr) {}                 // default constructor
    Function(const Function &);                              // copy constructor
    Function(Function &&);                                   // move constructor
    template <typename Functor> Function(Functor &&);        // generalized constructor

    // destructor
    ~Function() { delete mFunctorWrapper; }

    // copy/move operations
    Function &operator=(Function const &);                          // copy assignmaent operator
    Function &operator=(Function &&);                               // move assignment operator 
    template <typename Functor> Function &operator=(Functor &&);    // generalized assignment operator

    // overloaded function call operator
    ReturnType operator()(Args...);
private:
    FunctorWrapperBase<ReturnType(Args...)> *mFunctorWrapper;
};

template <typename ReturnType, typename... Args>
Function<ReturnType(Args...)>::Function(const Function &other) : mFunctorWrapper(nullptr)
{
    if (other.mFunctorWrapper)
        mFunctorWrapper = other.mFunctorWrapper->Clone();
}

template <typename ReturnType, typename... Args>
Function<ReturnType(Args...)>::Function(Function &&other) :  mFunctorWrapper(other.mFunctorWrapper)
{
    other.mFunctorWrapper = nullptr;
}

template <typename ReturnType, typename... Args>
template <typename Functor>
Function<ReturnType(Args...)>::Function(Functor &&functor)
{
    // remove reference if l-value (template type argument deduced as Functor &)
    mFunctorWrapper = new FunctorWrapper<typename std::remove_reference<Functor>::type, ReturnType(Args...)>(std::forward<Functor>(functor));
}

template <typename ReturnType, typename... Args>
Function<ReturnType(Args...)> &Function<ReturnType(Args...)>::operator=(const Function &other)
{
    mFunctorWrapper = other.mFunctorWrapper->Clone();

    return *this;
}

template <typename ReturnType, typename... Args>
Function<ReturnType(Args...)> &Function<ReturnType(Args...)>::operator=(Function &&other)
{
    mFunctorWrapper = other.mFunctorWrapper;
    other.mFunctorWrapper = nullptr;

    return *this;
}

template <typename ReturnType, typename... Args>
template <typename Functor>
Function<ReturnType(Args...)> &Function<ReturnType(Args...)>::operator=(Functor &&functor)
{
    mFunctorWrapper = new FunctorWrapper<typename std::remove_reference<Functor>::type, ReturnType(Args...)>(std::forward<Functor>(functor));
}

template <typename ReturnType, typename... Args>
ReturnType Function<ReturnType(Args...)>::operator()(Args... args)
{
    mFunctorWrapper->Invoke(args...);
}

这个类只管理为FunctorWrapper类型的对象分配的内存,FunctorWrapper是一个表示不同类型的仿函数(或callables)的类模板。

如果我从一个函数对象构造一个Function类型的对象,一个lambda或一个指向函数的指针它一切顺利(我可以调用该对象并调用相对函数)。

但是如果我尝试从另一个Function复制构造(或移动构造)一个函数,编译器只会将调用绑定到带有任意对象的构造函数(带有模板参数Functor的通用构造函数和作为函数参数的通用引用),崩溃。

我想如果我调用构造函数,如:

Function<void(double)> fp4(&FreeFunction);
fp4(1.2);

Function<void(double)> fp5 = fp4;  // copy construction

应该调用复制构造函数,因为它更专业。 我按照书上的例子,但我一定做错了。

我认为这是书中的缺陷。

应该调用复制构造函数,因为它更专业

template <typename Functor> Function(Functor &&); 是一个更好的匹配。

在将typename Functor推导为Function<...> & ,构造函数变为Function(Function &); ,这是一个比Function(const Function &);更好的匹配Function(const Function &); 如果你传递一个非const对象。

您可以使用SFINAE解决此问题:

template
<
    typename Functor,
    typename = std::enable_if_t<!std::is_same_v<Function,
        std::remove_cv_t<std::remove_reference_t<Functor>>>>
>
Function(Functor &&);

您需要使用赋值运算符执行相同的操作。 或者,你可以简单地删除它(分配一个仿函数仍然可以工作,因为编译器应该调用Function(Functor &&)然后调用move赋值)。

是的,遗憾的是转发引用版本比复制构造函数更好,这需要隐式转换为对const的引用。

你可以把约束作为

template <typename Functor, std::enable_if_t<!std::is_base_of_v<Function, std::decay_t<Functor>>>* = nullptr> 
Function(Functor &&);  

PS:我使用std::is_base_of而不是std::is_same ,对于可能继承Function的情况,并且在派生类的复制构造Function可以使用带派生的参数调用Function的复制构造Function班级类型。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM