【发布时间】:2019-07-21 15:34:06
【问题描述】:
我正在阅读“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 类型的对象分配的内存,它是一个类模板,代表不同类型的仿函数(或可调用对象)。
如果我从函数对象、lambda 或指向函数的指针构造函数类型的对象,一切顺利(我可以调用对象并调用相关函数)。
但是,如果我尝试从另一个函数复制构造(或移动构造)函数,编译器只会将调用绑定到接受任意对象的构造函数(具有模板参数 Functor 和通用引用作为函数参数的通用构造函数),导致崩溃。
我想如果我像这样调用构造函数:
Function<void(double)> fp4(&FreeFunction);
fp4(1.2);
Function<void(double)> fp5 = fp4; // copy construction
应该调用复制构造函数,因为它更专业。 我按照书上的例子做了,但我一定做错了什么。
【问题讨论】:
-
为什么在这种情况下应该调用复制构造函数
fp5 = fp4?复制 ctor 在其签名中有const。但是fp4是非常量对象。因此,完美转发的重载比F(const F&)具有更好的匹配性,并且在这种情况下使用它。当您将fp4更改为 const 对象时,将调用复制 ctor。因为当编译器有两个具有相同匹配的重载时——一个是普通函数,另一个是模板版本,普通函数是首选。
标签: c++ templates copy-constructor