虚函数与泛型编程
Virtual Functions and Generic Programming
假设我有一个模板类:
template <class T>
class Foo
{
public:
explicit Foo(const T& value)
: m_Value(value)
{
}
bool Bar(const T& value)
{
return m_Value == value;
}
private:
T m_Value;
};
假设我有其他用户类型例如:
class A
{
};
那么这段代码是完全有效的,即使类A没有定义相等操作符:
int main(int argc, char* argv[])
{
A a;
Foo<A> foo(a);
return 0;
}
但如果我做 Foo:: Bar () 虚拟:
virtual bool Bar(const T& value)
{
return m_Value == value;
}
代码不再编译:
错误C2676: binary '==': 'A'没有定义此操作符或转换为预定义操作符
可接受的类型我完全理解为什么这是一个问题。如果我错了,请纠正我,但我的理解是,因为函数是虚拟的,编译器必须编译函数(即使它从未被调用),以便它可以在Foo的v表中引用它。我想知道是否有办法解决这个问题。我希望有一个模板类来处理可能只实现部分接口的泛型类型。只要不使用丢失的位,代码应该可以很好地编译。这与许多STD容器的工作原理类似,但它们不使用虚函数。
我该怎么做?是否有一个优雅的解决方案?
正如上文Kerrek SB所解释的,虚函数总是在模板实例化时实例化的。因此,当不使用虚拟方法时,没有办法让您的程序编译得很好和,如果使用它并且您想要包装的类不提供自己的operator==
,则无法编译。
但是,您可以使程序在运行时崩溃(使用assert
/terminate
)或抛出异常。
免责声明:我不认为这是一个好主意去做你正在尝试做的事情,因为它允许创建不支持他们声称提供的接口的类。使用以下内容,风险自负。
这里的方法是为你想要提供的每个方法使用自定义类型特征,即使包装的类本身没有实现它。在上面的例子中,这只是operator==
,对应的代码看起来像这样:
namespace traits {
template <typename T>
using operator_eq_t = decltype(std::declval<T>() == std::declval<T>());
template <typename, typename = void>
struct has_operator_eq : std::false_type {};
// check that operator== is defined and returns the correct type `bool`.
template <typename T>
struct has_operator_eq<T, std::void_t<operator_eq_t<T>>>
: std::is_same<operator_eq_t<T>, bool> {};
} // namespace traits
如果你还不能访问c++1z,你可以创建自己的std::void_t
版本,其他的都是有效的c++ 14:
template <typename...>
using void_t = void
准备好之后,您可以创建带有标记dispatch的包装器类模板:
template <typename T>
class Foo : public IFoo<T> {
public:
explicit Foo(T const& value)
: m_Value(value) {
}
bool Bar(T const& value) override {
return BarImpl(value, traits::has_operator_eq<T>{});
}
private:
T m_Value;
bool BarImpl(T const& value, std::false_type) {
// some sensible default, in this case you might
// consider just to return false
assert(!"Called `Bar` on class that does not implement `operator==`.");
throw std::logic_error("Called `Bar` on class that does not implement `operator==`.");
}
bool BarImpl(T const& value, std::true_type) {
return value == m_Value;
}
};
相关文章:
- 泛型模板函数始终返回整数值
- 使用泛型编程的基本数据结构
- 在泛型编程中使用新的放置
- 继承泛型成员函数
- 泛型成员函数定义
- 在泛型编程中选择类型参数
- 在泛型编程C++重载增量运算符
- 处理C++泛型编程中的空分配
- C++14:具有泛型std::函数作为类成员的泛型lambda
- 有关C++泛型编程的错误
- 绑定泛型成员函数
- 在泛型编程中,需要在派生类中重新声明基类成员函数
- 将泛型编程与多态性混合在一起
- C++泛型编程 CRTP 基类继承自派生类型提供的类
- 多态树类中的双指针upcast(再次)、shared_ptr和泛型setChild函数
- 为什么泛型编程设计更喜欢自由函数而不是成员函数
- C++函数式和泛型编程[使用MySQL连接器示例]
- 继承和虚函数与泛型编程
- 虚函数与泛型编程
- 概念与复制构造函数冲突的泛型编程