我努力一步一步地编写示例,使其清晰易懂。
此处显示的object BaseCreator公开了一个create函数,该函数使用一个内部类NewObject来分配一个t类型的新对象。new object类的默认方法是使用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 }));
我们还可以为特定对象和特定类型的创建者声明特定的创建方法。这里举例说明使用组222的创建者创建对象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.1f,0.7f,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。
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;
}
};
如果我尝试创建一个对象,让我们使用这个Creator333说B:
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> ]
但这很奇怪,因为该函数确实应该得到两个参数,如下所示:
>
Create333::create
- 获取一个包含一个元素的包 std::vector({ 0.1f,0.2f})
它调用其基本计算器<code>BaseCreator
BaseCreator
那么问题是什么,怎么解决呢?
谢谢
以下是一个解决方案,但不是答案,这意味着代码有效,但我不明白为什么这个工作,而问题中的那个不起作用。因此,如果有人可以描述原因,我相信这将有助于许多人更深入地了解这个主题。
感谢@Kuba comment,我根据他建议的单词进行了搜索,并在这个stackoverflow问题中找到了一个代码,启发了我以下解决方案:
我为Creator333
添加了一个Helper
,如下所示。它有助于将输入包拆分为所需的两部分:附加整数和来自应用程序代码的原始包。但我还必须将特殊的创建代码移入其中。
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;
}
};
};
专门化< code>BaseCreator
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)...);
}
};
当我编译时,我得到了这些错误:
以下是我的代码:< br > 一开始我只是重载了函数,发现有很多类似的代码。所以我正在考虑使用可变参数模板来获得更好的设计。(如果两个重载函数相似,如何做出更好的设计) 但是我不知道为什么会有错误:< br > main.cpp:27: 8:错误:没有匹配函数调用'getChar'ch=getChar(1, std::forward(str)...); 主要的cpp:37:2:注意:在函数模板专门
要解决的问题: 怎么创建一个拥有1个、2个或者更多的初始化器的类? 怎么避免创建一个实例而只拷贝部分的结果? 怎么创建一个元组? 最后的问题是关键所在:考虑一下元组!如果你能创建并且访问一般的元组,那么剩下的问题也将迎刃而解。 这里有一个例子(摘自“可变参数模板简述(A brief introduction to Variadic templates)”(参见参考)),要构建一个广义的、类型安全的
在C++11之前,类模板和函数模板只能含有固定数量的模板参数。C++11增强了模板功能,允许模板定义中包含0到任意个模板参数,这就是可变参数模板。可变参数模板的加入使得C++11的功能变得更加强大,而由此也带来了许多神奇的用法。 可变参数模板 可变参数模板和普通模板的语义是一样的,只是写法上稍有区别,声明可变参数模板时需要在typename或class后面带上省略号...: template<ty
受这个答案的启发,我生成了这段代码,其输出取决于编译器: 如果使用 GCC 11 编译,调用
我希望打印函数根据“值”的类型来做不同的事情。