如何解决除了可变参数模板参数之外的输入参数未能编译
我努力一步一步地编写示例,使其清晰易懂。
此处显示的对象 BaseCreator 公开了一个创建函数,该函数使用内部类 NewObject 来分配类型为 T 的新对象。类 NewObject 默认方法是使用 new 运算符的常用方法,但可以使用专门化来更改它以使用不同的过程。我们稍后会看到。
template <typename F>
class BaseCreator
{
public:
BaseCreator() = default;
virtual ~BaseCreator() = default;
// create function
template <typename T,typename... Args>
std::shared_ptr<T> create(Args&&... parameters)
{
return std::shared_ptr<T>(NewObject<T,Args...>().get(std::forward<Args>(parameters)...));
}
private:
// creator object with default functionality to create a new object
template <typename T,typename... Args>
struct NewObject
{
T* get(Args&&... parameters)
{
return new T(std::forward<Args>(parameters)...);
}
};
};
这很好用,例如假设我们有以下对象类型:
struct A
{
A(int i_i,const std::string& i_s) : i(i_i),s(i_s) {}
void addVal(int i_i) { i+=i_i; }
int i = 0;
std::string s;
};
struct B
{
B(const std::vector<float>& i_v) : v(i_v) {}
void addVal(int i_i) { v.push_back((float)i_i); }
std::vector<float> v;
};
我们可以轻松创建它们,例如:
// declare type for a creator identity
struct Group111 {};
// creator object
BaseCreator<Group111> cCreator111;
// creating A and B
std::shared_ptr<A> spA = cCreator111.create<A>(5,"Hello");
std::shared_ptr<B> spB = cCreator111.create<B>(std::vector<float>({ 0.5f,0.1f,0.7f,0.9f }));
我们还可以为特定对象和特定类型的创建者声明特定的创建方法。例如,使用 Group222 的创建者创建对象 A 的特化示例:
// declare type for a creator identity
struct Group222 {};
// specialize NewObject for BaseCreator<Group222> for creating A
template<>
template< typename... Args>
struct BaseCreator<Group222>::NewObject<A,Args...>
{
A* get(int i_factor,int i_i,const std::string& i_s)
{
A* p = new A(i_i,i_s);
p->i *= i_factor;
return p;
}
};
使用 Group222 类型的创建者创建对象 A 的方法与默认方法不同。
// creator object
BaseCreator<Group222> cCreator222;
// creating A with creator of Group222 needs Now additional input argument
std::shared_ptr<A> spA = cCreator222.create<A>(3,5,"Hello");
// creating A with creator of Group222 is the same as creating using creator cCreator111
std::shared_ptr<B> spB = cCreator222.create<B>(std::vector<float>({ 0.5f,0.9f }));
现在的问题:)
现在,我想派生一个新的 BaseCreator 来拥有以下一个,如您所见,它具有代理创建函数,并使用额外的整数调用其基类 1:
class Creator333 : public BaseCreator<Creator333>
{
public:
Creator333() = default;
virtual ~Creator333() = default;
// creator
template <typename T,typename... Args>
std::shared_ptr<T> create(Args&&... parameters)
{
int adder = 5; // just for the example
return std::shared_ptr<T>(BaseCreator<Creator333>::create<T>(adder,std::forward<Args>(parameters)...));
}
};
它带有专门的 BaseCreator<Creator333>::NewObject
,它应该为任何对象处理这个额外的整数(在这个例子中 - 假设对象有一个名为 addVal() 的成员函数)
template<>
template<typename T,typename... Args>
struct BaseCreator<Creator333>::NewObject<T,Args...>
{
T* get(int i_adder,Args&&... parameters)
{
T* p = new T(std::forward<Args>(parameters)...);
p->addVal(i_adder);
return p;
}
};
如果我要尝试创建一个对象,假设 B 使用这个 Creator333:
Creator333 cCreator333;
// creation of B using Creator333
std::shared_ptr<B> spB3 = cCreator333.create<B>(std::vector<float>({ 0.1f,0.2f}));
error C2660: 'BaseCreator<Creator333>::NewObject<T,int &,_Ty>::get': function does not take 2 arguments
1> with
1> [
1> T=B,1> _Ty=std::vector<float,std::allocator<float>>
1> ]
但这很奇怪,因为函数确实应该得到如下两个参数:
-
它用额外的整数调用它的基类
BaseCreator<Create333>::create
,因此BaseCreator<Create333>::create
得到一个包含两个元素的包:int(5) 和 std::vector({ 0.1f,0.2f}) -
BaseCreator<Create333>::create`` calls
BaseCreator::NewObject.get``` 其中包的第一个元素用于 get(adder),包的另一个元素用于 get(Args ...
那么问题是什么以及如何解决?
谢谢
解决方法
以下是解决方案但不是答案, 这意味着代码有效,但我不明白为什么这项工作和问题中的那个没有。因此,如果有人可以描述原因,我相信这将有助于许多人更深入地了解该主题。
感谢@Kuba 的评论,我根据他建议的词进行了搜索,并在此 stackoverflow question 中找到了一个代码,这激发了我的以下解决方案:
我为 Helper
添加了一个 Creator333
类,如下所示。它有助于将输入包拆分为所需的两部分:附加整数和来自应用程序代码的原始包。但我也不得不将特殊的创建代码移入其中。
class Creator333 : public BaseCreator<Creator333>
{
public:
Creator333() = default;
virtual ~Creator333() = default;
// creator
template <typename T,typename... Args>
std::shared_ptr<T> create(Args&&... parameters)
{
int adder = 5; // just for the example
return std::shared_ptr<T>(BaseCreator<Creator333>::create<T>(adder,std::forward<Args>(parameters)...));
}
// helper class for splitting given pack into desired two parts:
// the additional integer and the original pack came from the application code
template<typename T,typename FirstTypeT,typename... Args>
struct Helper
{
T* get(FirstTypeT i_adder,Args&&... parameters)
{
T* p = new T(std::forward<Args>(parameters)...);
p->addVal(i_adder);
return p;
}
};
};
特化 BaseCreator<Creator333>::NewObject
本身现在只需要使用 Helper,如下所示:
template<>
template<typename T,typename... Args>
struct BaseCreator<Creator333>::NewObject<T,Args...>
{
T* get(Args&&... parameters)
{
return Creator333::Helper<T,Args... >().get(std::forward<Args>(parameters)...);
}
};
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。