编辑可能无法完成,请参阅Clean implementation of function template taking function pointer虽然答案1有一个C宏解决方法https://stackoverflow.com/a/18706623/2332068
我将一个函数传递给一个模板,成为构造函数的预提供参数,但是还需要在该函数上使用decltype
将函数类型传递给unique_ptr<...>
模板实例化器( ?是正确的词)
如果我预先使用decltype
作为额外的模板参数,那么它是有效的,但如果我在作为参数传递的函数的模板内调用它,则不行。
我正在使用g ++ 4.9.2,并在此扩展我的探索Calling inherited template constructor of unique_ptr subclass,其中我将unique_ptr
子类化为具有固定的析构函数,我发现一些析构函数不会返回void
,所以我想要一个更通用的模板,不需要指定析构函数类型。
我目前的代码是:
void free_int(int* p) {
delete p;
}
template<typename T, void (*D)(T*)>
class unique_dptr : public std::unique_ptr<T, decltype(D)> {
public: unique_dptr(T* t) : std::unique_ptr<T, decltype(D)>(t, D) { };
};
using int_ptr = unique_dptr<int, ::free_int>;
int_ptr i(new int(2));
但请注意void (*D)(T*)
调用签名将析构函数限制为void函数,该函数指向T
在此表单中正常使用unique_ptr
:
unique_ptr<foo, decltype(&::free_foo)>
我希望有这样的东西:
template<typename T, typename D>
class unique_gptr : public std::unique_ptr<T, decltype(&D)> {
public: unique_gptr(T* t) : std::unique_ptr<T, decltype(&D)>(t, D) { };
};
using int_gptr = unique_gptr<int, ::free_int>;
int_gptr ig(new int(2));
但编译器讨厌它:
error: template argument 2 is invalid
class unique_gptr : public std::unique_ptr<T, decltype(&D)> {
^
毫无疑问,古老的C-macro风格标记粘贴是我错误的目标。
我尝试从&
删除decltype(&D)
,但会留下错误:
error: argument to decltype must be an expression
但是没关系:
template<typename T, typename D, D F>
class unique_gptr : public std::unique_ptr<T, D> {
public: unique_gptr(T* t) : std::unique_ptr<T, D>(t, F) { };
};
using int_gptr = unique_gptr<int, decltype(&::free_int), ::free_int>;
int_gptr ig(new int(2));
但是我想知道我做错了什么我无法管理将decltype(&::free_int)
移到模板中。
我意识到我可以为其他固定的自由函数类型编写额外的特化,替换void(*)(void*)
我意识到我可以为我的类型覆盖std::default_delete
。
但这实际上是模板构图中的练习
答案 0 :(得分:2)
您不能将decltype
与类型一起使用,因为目标是获取变量的类型。但在decltype(&D)
中,D
是一种类型。
我宁愿通过模板函数:
template<typename T, typename D, D F>
class unique_gptr : public std::unique_ptr<T, D> {
public: unique_gptr(T* t) : std::unique_ptr<T, D>(t, F) { };
};
template <typename T, typename D>
unique_gptr<T, D F> make_unique_gptr(T pointer, D deleter)
{
return unique_gptr<T, D, deleter>(pointer);
}
auto ptr = make_unique(new int(2), ::free_int);
答案 1 :(得分:2)
我认为对于c ++ 11来说,实现你想要的东西是不可能的。
template<typename T, typename D> class unique_gptr : public std::unique_ptr<T, decltype(&D)> { public: unique_gptr(T* t) : std::unique_ptr<T, decltype(&D)>(t, D) { }; }; using int_gptr = unique_gptr<int, ::free_int>; int_gptr ig(new int(2));
请注意,decltype
已应用于D
,其被声明为typename
。所以D
是一种类型。但decltype
不能用于类型。
首先,代码尝试获取类型的地址(&
)。其次,decltype
的论点应该是表达式,但不是类型或“类型的地址”。为了便于理解,我们可以说decltype
期望它的参数是一个“变量”,如下例所示。
int main()
{
int i = 10;
decltype(i) j;
decltype(int) k; /* Compiler error. */
decltype(&int) l; /* Compiler error. */
return 0;
}
您还希望编译器将D
替换为::free_int
。并且::free_int
作为non-type template参数传入。但是D
是类型模板参数。非类型模板参数以实际类型(例如int
,struct a*
或类型模板名称)开头。类型模板参数以typename
或class
开头。非类型模板参数的简单示例
template<int INIT>
void func2(void)
{
decltype(INIT) j = INIT;
}
int main()
{
func2<10>();
return 0;
}
当你传递像::free_int
这样的函数指针时,你需要非类型模板参数,它必须以类型开头。并且您希望函数指针的类型是“可替换的”。因此,函数指针的类型必须是类型模板参数。这些使它们成为两个模板参数。
这就是你需要template<typename T, typename D, D F>
中三个模板参数的原因,这是你得到的最佳结果。
答案 2 :(得分:1)
你可以使用一些宏魔术:
template<class T, class D, D d>
struct UniqueDeleter : public std::unique_ptr<T, D> {
UniqueDeleter(T* t) : std::unique_ptr<T, D>(t, d) { };
};
template<class R, class T>
T decl_unique_deleter_ptr(R (*d)(T*));
#define DECL_UNIQUE_DELETER1(f) UniqueDeleter<decltype(decl_unique_deleter_ptr(&f)), decltype(&f), &f>
#define DECL_UNIQUE_DELETER2(T, f) UniqueDeleter<T, decltype(&f), &f>
#define DECL_UNIQUE_DELETER_GET_MACRO(_1, _2, NAME, ...) NAME
#define DECL_UNIQUE_DELETER_EXPAND(x) x
#define decl_unique_deleter(...) DECL_UNIQUE_DELETER_EXPAND(DECL_UNIQUE_DELETER_GET_MACRO( \
__VA_ARGS__, DECL_UNIQUE_DELETER2, DECL_UNIQUE_DELETER1, _)(__VA_ARGS__))
现在您可以像这样使用它:
decl_unique_deleter(int, free_int) ig(new int(2));
或using
以及更多魔法:
using int_gptr = decl_unique_deleter(free_int); // If accepted pointer type matches.
int_gptr ig(new int(2));
我可能还会推荐另一种解决方案:
auto i = new int(2);
BOOST_SCOPE_EXIT_ALL(&) { delete i; };