如果找到函数,则启用复制构造函数
Enable Copy Constructor if function is found
我有一个围绕 Foo*
的 RAII 包装器,其中 Foo
是一个库。
class 看起来很像:
struct Handle{
Foo* p;
Handle(): p(foo_new()){}
Handle(Handle&& f): p(std::exchange(f.p, nullptr)){}
Handle(const Handle& f){
p = foo_clone(f.p);
}
};
为简洁起见,省略了错误处理和赋值运算符。
现在的问题是,foo_clone
在 1 个库版本中可用,但在较早的版本中不可用,并且包装器应该支持两者。没有 *_VERSION
宏可供我检查,所以我需要用 C++ 而不是预处理器来检查。
我想到了类似的东西:
template<class T, decltype(foo_clone(std::declval<T>().p)) = nullptr>
Handle(const T& f){...}
但这不起作用:定义的 move-ctor 要求我逐字添加一个复制 ctor 作为 Handle(const Handle&)
,似乎不允许模板欺骗,否则编译器认为复制 ctor 被隐式删除。
我能做什么?
你确实不能SFINAE那个不应该是模板的特殊成员。
因此您可以模板 class 本身:
// I let you implement traits has_foo_clone<T>
template <typename T, bool = has_foo_clone<T>::value>
struct HandleImpl
{
T* p;
HandleImpl(): p(foo_new()) {}
HandleImpl(HandleImpl&& f): p(std::exchange(f.p, nullptr)){}
HandleImpl(const HandleImpl& f){ p = foo_clone(f.p); }
};
template <typename T>
struct HandleImpl<T, false>
{
T* p;
HandleImpl(): p(foo_new()) {}
HandleImpl(HandleImpl&& f): p(std::exchange(f.p, nullptr)){}
HandleImpl(const HandleImpl& f) = delete;
};
using Handle = HandleImpl<Foo>;
在 C++20 中,由于 requires
到 "discard" 方法,您可能会做得更好:
template <typename T>
struct HandleImpl
{
T* p;
HandleImpl(): p(foo_new()) {}
HandleImpl(HandleImpl&& f): p(std::exchange(f.p, nullptr)){}
HandleImpl(const HandleImpl& f) requires(has_foo_clone<T>::value) { p = foo_clone(f.p); }
};
using Handle = HandleImpl<Foo>;
我有一个围绕 Foo*
的 RAII 包装器,其中 Foo
是一个库。
class 看起来很像:
struct Handle{
Foo* p;
Handle(): p(foo_new()){}
Handle(Handle&& f): p(std::exchange(f.p, nullptr)){}
Handle(const Handle& f){
p = foo_clone(f.p);
}
};
为简洁起见,省略了错误处理和赋值运算符。
现在的问题是,foo_clone
在 1 个库版本中可用,但在较早的版本中不可用,并且包装器应该支持两者。没有 *_VERSION
宏可供我检查,所以我需要用 C++ 而不是预处理器来检查。
我想到了类似的东西:
template<class T, decltype(foo_clone(std::declval<T>().p)) = nullptr>
Handle(const T& f){...}
但这不起作用:定义的 move-ctor 要求我逐字添加一个复制 ctor 作为 Handle(const Handle&)
,似乎不允许模板欺骗,否则编译器认为复制 ctor 被隐式删除。
我能做什么?
你确实不能SFINAE那个不应该是模板的特殊成员。
因此您可以模板 class 本身:
// I let you implement traits has_foo_clone<T>
template <typename T, bool = has_foo_clone<T>::value>
struct HandleImpl
{
T* p;
HandleImpl(): p(foo_new()) {}
HandleImpl(HandleImpl&& f): p(std::exchange(f.p, nullptr)){}
HandleImpl(const HandleImpl& f){ p = foo_clone(f.p); }
};
template <typename T>
struct HandleImpl<T, false>
{
T* p;
HandleImpl(): p(foo_new()) {}
HandleImpl(HandleImpl&& f): p(std::exchange(f.p, nullptr)){}
HandleImpl(const HandleImpl& f) = delete;
};
using Handle = HandleImpl<Foo>;
在 C++20 中,由于 requires
到 "discard" 方法,您可能会做得更好:
template <typename T>
struct HandleImpl
{
T* p;
HandleImpl(): p(foo_new()) {}
HandleImpl(HandleImpl&& f): p(std::exchange(f.p, nullptr)){}
HandleImpl(const HandleImpl& f) requires(has_foo_clone<T>::value) { p = foo_clone(f.p); }
};
using Handle = HandleImpl<Foo>;