有没有一种方法可以使用SFINAE来检测一个类型是否实现了给定的抽象基类
Is there a way to use SFINAE to detect if a type implements a given abstract base class?
下面是这个问题的简单用例。(注意:我意识到这里显示的代码模式可能不被认为是最佳实践;示例代码只是为了说明手头的主题(
目前,我有一个方便的小模板函数,它将从堆中分配任意给定对象的副本,并返回该副本:
template<typename T> inline T * CloneStaticObject(const T & item)
{
return new T(item);
}
适用于任何带有复制构造函数的类型。。。直到我传入一个对基类的引用,然后我就遇到了一点一点的对象切片问题。
因此,为了处理这个问题,我还有一个很好的OOP风格的克隆接口,我可以使用它,并配有一个CloneDynamicObject(const ICloneable &)
函数,它将正确地克隆从ICloneable
继承的任何对象,无论传入引用的类型是什么:
class ICloneable
{
public:
virtual ~ICloneable() {/* empty */}
virtual ICloneable Clone() const = 0;
};
class MyBaseClass : public ICloneable
{
public:
MyBaseClass() {/* empty */}
virtual ICloneable * Clone() const {return new MyBaseClass(*this);}
};
class MySubClass : public MyBaseClass
{
public:
MySubClass() {/* empty */}
virtual ICloneable * Clone() const {return new MySubClass(*this);}
};
template<typename T> inline T * CloneDynamicObject(const T & item)
{
return static_cast<T *>(item.Clone());
}
这也很好,只要我小心地只传递一个引用ICloneable对象的参数。
但现在逐渐优雅起来了,我想制作一个CloneAnyObject(const T & item)
函数,无论发生什么,它都会做正确的事情,例如:
// This doesn't work but it shows the idea
template<typeName T> inline T * CloneAnyObject(const T & item)
{
const ICloneable * cloneMe = dynamic_cast<const ICloneable *>(&item);
if (cloneMe) return CloneDynamicObject(*cloneMe)
else return CloneStaticObject(item);
}
上面的实现几乎实现了我想要的,除了它有两个问题:
dynamic_cast<>
不适用于所有类型- 即使是这样,
dynamic_cast()
也会在运行时测试对象,如果可能的话,我希望通过在编译时评估ICloneability测试来避免这种开销
我的问题是,是否有任何方法可以使用SFINAE正确实现CloneAnyObject()
功能?
(请注意,我知道SFINAE测试typename是否有一个具有给定名称的方法的技巧,我认为这是一种非常有用的技术,但这并不是我在这里想要的;相反,我想要的是一种测试类型是否从接口继承的方法(
您可以使用std::is_base_of特性静态地确定一个类型是否派生自另一个类型。它可以按如下方式将函数拆分为一个派生类型版本和一个其他类型版本:
// For derived types
template <typename T, std::enable_if_t<std::is_base_of_v<ICloneable, T>, int> = 0>
inline T * CloneAnyObject(const T & item) {
return CloneDynamicObject(item);
}
// For non-derived types (note the !)
template <typename T, std::enable_if_t<!std::is_base_of_v<ICloneable, T>, int> = 0>
inline T * CloneAnyObject(const T & item) {
return CloneStaticObject(item);
}
如果您使用的是C++17,您也可以使用if constexpr
来简化它,如Jarod42的回答所示。
您可能有两个过载:
template <typeName T>
std::enable_if_t<std::is_base_of<ICloneable , T>::value, T*> /* SFINAE */
CloneAnyObject(const T& item)
{
return CloneDynamicObject(item);
}
template <typeName T>
std::enable_if_t<!std::is_base_of<ICloneable , T>::value, T*> /* SFINAE */
CloneAnyObject(const T& item)
{
return CloneStaticObject(item);
}
使用C++17,您可以进行
template <typeName T>
T* CloneAnyObject(const T& item)
{
if constexpr (std::is_base_of<ICloneable, T>::value) {
return CloneDynamicObject(item);
} else {
return CloneStaticObject(item);
}
}
相关文章:
- 使用简单类型列表实现的指数编译时间.为什么
- 实现有界基元类型的c++
- 根据C++标准的定义实现"is_similar"类型特征
- 为什么 std::lerp 不适用于任何已实现所需操作的类型?
- C ++类型特征:确保子类实现方法
- 为自定义打印调试实现传递任何类型的变量
- 为 Sql 服务器实现 odbc 包装器.将数据库数据读取为字符或要求驱动程序将数据转换为 C 类型
- 将C++子类成员函数(虚拟实现)传递给 C 类型函数指针
- 使用智能指针指向 C 库中的结构,该结构通过 typedef 隐藏实现(即不完整的类型)
- 在 OpenCL 内核中实现半精度浮点数据类型
- 在头文件中使用opencv类型来实现未定义的标识符
- 如何实现对参数顺序不可知的std::same_as的广义形式(即对于两个以上的类型参数)
- 如何实现一个接受任何容器类型的函数
- 有没有一种方法可以使用SFINAE来检测一个类型是否实现了给定的抽象基类
- 实现类型类向量的元素
- 如何在 python 中实现 c++ 类型结构
- 我能否在 uint_fast64_t 和无符号长整型之间实现类型等效性
- 从Bloch的Effective Java in C++实现类型安全的异构容器(VS2010)
- SFINAE使用模板、专门化和实现类型擦除
- 使用的实现类型