丢失带有可变模板参数的右值限定符
Loss of rvalue qualifier with variadic template arguments
我正在尝试为我的应用程序编写一个具有自动自注册类型的通用工厂类。
为了允许灵活性,这个工厂有一个可变的模板形参用于构造函数实参;也就是说,它允许默认构造函数或需要任意数量参数的构造函数。参数名是不言自明的;AbstractType是工厂的抽象基类;返回的对象将是该类型的std::shared_ptr
。
这个泛型工厂工作得很好,我为它编写的所有测试都工作得很好,直到我试图为包含不允许复制构造或赋值的类(作为数据成员)的特定类层次结构创建一个工厂。我试图通过使用模板参数的右值引用来解决这个问题;然而,这并不以我所期望的方式工作。具体来说,如果我将工厂实例定义为接受A&&
类型的构造函数参数,则会失败,并出现一个错误,告诉我没有从a到a的转换&&。
在本例中,My_Abstract
、Data_Context
和Other_Class
在其他地方声明。如上所述,这里的想法是具体类型CT
将有一个签名为:
class CT {
CT(Data_Context&&, Other_Class const&);
/* ... */
};
class My_Abstract; // forward declaration
template <class ConcreteType>
using My_Factory_Registrar =
Factory_Registrar<ConcreteType, My_Abstract, Data_Context &&, Other_Class const&>;
using My_Factory =
Generic_Factory<My_Abstract, Data_Context &&, Other_Class const&>;
也许我在这里遗漏了一些基本的东西,但是当我修改代码为:
template <class ConcreteType>
using My_Factory_Registrar =
Factory_Registrar<ConcreteType, My_Abstract, Data_Context const&, Other_Class const&>;
using My_Factory =
Generic_Factory<ConcreteType, Data_Context const&, Other_Class const&>;
然后一切都编译并正常工作。我很清楚,r值可以用于const引用参数,所以我并不困惑为什么这工作,就像我完全困惑为什么第一个代码片段不工作一样。这看起来就像是在可变模板扩展过程中删除了右值引用限定符。
我不确定它是否有助于澄清事情,但是工厂类本身的代码如下:
template <class AbstractType, class...ConstructorArgs>
class Generic_Factory{
public:
static std::shared_ptr<AbstractType> Construct(std::string key, ConstructorArgs... arguments){
auto it = Get_Registry()->find(key);
if (it == Get_Registry()->cend())
return nullptr;
auto constructor = it->second;
return constructor(arguments...);
}
using Constructor_t = std::function<std::shared_ptr<AbstractType>(ConstructorArgs...)>;
using Registry_t = std::map< std::string, Constructor_t>;
Generic_Factory(Generic_Factory const&) = delete;
Generic_Factory& operator=(Generic_Factory const&) = delete;
protected:
Generic_Factory(){}
static Registry_t* Get_Registry();
private:
static Registry_t* _registry_;
};
template <class ConcreteType, class AbstractType, class...ConstructorArgs>
struct Factory_Registrar : private Generic_Factory<AbstractType, ConstructorArgs...>{
using Factory = Generic_Factory<AbstractType, ConstructorArgs...>;
using Constructor_t = typename Factory::Constructor_t;
public:
Factory_Registrar(std::string const& designator, Constructor_t object_constructor){
auto registry = Factory::Get_Registry();
if (registry->find(designator) == registry->cend())
registry->insert(std::make_pair(designator, object_constructor));
}
};
谢谢你的帮助。
Shmuel
完美转发用于这些情况。你的代码很长。我使用make_unique
的简化版本进行演示。
template <typename T, typename ...Args>
auto make_unique(Args&&... args) -> std::unique_ptr<T>
{
return std::unique_ptr<T>{new T(std::forward<Args>(args)...)};
}
为了能够在不丢失类型信息的情况下转发右值输入参数,需要使用通用引用。典型的例子是:
template<class T>
void Forwarder(T&& t)
{
Func(std::forward<T>(t));
}
这样,就不会丢失类型信息,并且调用了正确的Func重载。
另一方面,如果Forwarder
的体调用了Func
(t),则只有Func的左值重载可以匹配。
- 如何反转整数参数包
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 如何使用默认参数等选择模板专业化
- 模板参数替换失败,并且未完成隐式转换
- 具有默认模板参数的多态类的模板推导失败
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 函数调用中参数的顺序重要吗
- 部分定义/别名模板模板参数
- 模板-模板参数推导:三个不同的编译器三种不同的行为
- 使用不带参数的函数访问结构元素
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 如何在OMNET++中指定与命令行参数组合的输出文件名
- 如何使用Luacneneneba API正确读取字符串和表参数
- 在派生函数中指定void*参数
- 视图中的参数推导失败:take_while
- static_assert在宏中,但也可以扩展到可以用作函数参数的东西
- 使用指向成员的指针将成员函数作为参数传递
- 没有名称的C++模板参数
- 如何将enable-if与模板参数和参数包一起使用