我正在编写一个名为Wraiiper
的资源管理类。最终目标是能够写出像
Wraiiper wr(new ClassA(), destroyA); // cleanup with destroyA
wr.push_back(new ClassB()); // cleanup with delete
因此它基本上是动态大小,接受任何类型,并使用delete
或自定义解除分配器删除。我想如果我向各种元素插入唯一指针,那么std::vector<boost:any>
会做同样的工作。代码( coliru link )遵循
#include <iostream>
#include <algorithm>
#include <vector>
namespace dpol
{ // destruction policies
template<typename Func>
struct Destruction
{
Func finalize;
Destruction(Func f) : finalize(f)
{
}
template<typename T>
void apply(T* data)
{
if (data) finalize(data);
}
};
template<>
struct Destruction<void>
{
template<typename T>
void apply(T* data)
{
delete data;
}
};
} // destruction policies
class Wraiiper
{
struct ResourceConcept
{
virtual ~ResourceConcept() {}
virtual void* get() = 0;
};
template<typename T, typename Func>
struct ResourceModel : ResourceConcept, dpol::Destruction<Func>
{
T* data;
ResourceModel(T* data)
: dpol::Destruction<Func>()
, data(data)
{ // a. One arg constructor
}
ResourceModel(T* data, Func f)
: dpol::Destruction<Func>(f)
, data(data)
{ // b. Two args constructor
}
~ResourceModel()
{
dpol::Destruction<Func>::apply(data);
}
void* get()
{
return data;
}
};
std::vector<ResourceConcept*> resource;
public:
template<typename T, typename Func>
Wraiiper(T* data, Func f)
{
resource.push_back(new ResourceModel<T, Func>(data, f));
}
template<typename T>
Wraiiper(T* data)
{
resource.push_back(new ResourceModel<T, void>(data));
}
~Wraiiper()
{
while (!resource.empty())
{
delete resource.back();
resource.pop_back();
}
}
template<typename T, typename Func>
T* push_back(T* data, Func f)
{
resource.push_back(new ResourceModel<T, Func>(data, f));
return get<T*>(resource.size()-1);
}
template<typename T>
T* push_back(T* data)
{
resource.push_back(new ResourceModel<T, void>(data));
return get<T*>(resource.size()-1);
}
template<typename T>
T get(std::size_t i = 0)
{
return (T)resource.at(0)->get();
}
};
struct A
{
int val;
A(int x) : val(x) {}
};
void dela(A *arg) { delete arg; }
int main()
{
Wraiiper wr(new A(2), dela); // compiles fine
Wraiiper wr2(new double); // error !
return 0;
}
以下错误困扰我
main.cpp:实例化&#39; struct Wraiiper :: ResourceModel&#39;:
main.cpp:79:7:来自Wraiiper :: Wraiiper(T *)[有T =双]&#39;
main.cpp:121:28:从这里要求
main.cpp:51:9:错误:参数类型无效&#39; void&#39;
ResourceModel(T* data, Func f) ^
main.cpp:51:9:错误:在声明中&#39; Wraiiper :: ResourceModel :: ResourceModel(T *,Func)&#39;
我的论点是,在实例化ResourceModel(T* data)
时应该选择带有一个参数Wraiiper::ResourceModel<double, void>
的构造函数(a),因为我用一个参数明确地调用它
这里发生了什么,为什么会出现错误,我怎么能克服它?
FWIW这也在Visual Studio 2012中失败(相同的错误)
答案 0 :(得分:1)
我的论点是在实例化Wraiiper :: ResourceModel时应该选择带有一个参数ResourceModel(T * data)的构造函数(a),因为我用一个参数显式调用它
调用函数不是问题;实例化ResourceModel<double, void>
是。您可能没有调用那个有问题的函数,但它仍然必须在实例化时在语义上有效:
[C++11: 14.7.1/1]:
[..] 类模板特化的隐式实例化会导致声明的隐式实例化,但不会导致定义或默认参数的实例化,类成员函数,成员类,作用域成员枚举,静态数据成员和成员模板; [..]
...只要它尝试使用double*
和void
,就不会达到该标准。
Clang's diagnostic output makes this marginally clearer:
clang++ -std=c++11 -O2 -pedantic -pthread main.cpp && ./a.out main.cpp:51:37: error: argument may not have 'void' type ResourceModel(T* data, Func f) ^ main.cpp:79:30: note: in instantiation of template class 'Wraiiper::ResourceModel<double, void>' requested here resource.push_back(new ResourceModel<T, void>(data)); ^ main.cpp:121:14: note: in instantiation of function template specialization 'Wraiiper::Wraiiper<double>' requested here Wraiiper wr2(new double); // error ! ^ 1 error generated.
否则,我猜您需要为
std::enable_if
案例专门ResourceModel
。另一种方法是将一个单数函数发送到<..., void>
而不是一个,但你仍然需要选择一个可通行的类型。