c++ - 函数参数能否保证一个类符合接口?
问题描述
是否可以让一个函数接受一个“基类”并指定它需要符合某个接口?例如:
class A{};
class ISomeInterface{..};
class B:public A, public ISomeInterface{};
class C:public A, public ISomeInterface{};
其他类(不是从 派生的A
)也可以使用ISomeInterface
,并不是每个派生的类A
都需要实现ISomeInterface
。现在我想让一个函数接受 A 的任何子类,只要它也在实现ISomeInterface
,所以像这样;
void doSomething(A<ISomeInterface> *a){}; // or (A&&ISomeInterface *a) or (A::ISomeInterface a*) or whatever
我不想直接指定 B 或 C 作为参数,但我希望它们作为参数。我唯一知道的是,我希望基类成为A
并且传递的任何子类A
都必须实现ISomeInterface
。在现代语言中,这真的很容易,但我似乎不知道如何在 C++ 中做到这一点。这是模板的用途吗?
解决方案
使用 C++20 概念,这是微不足道的:
#include <concepts>
struct iface {
virtual void do_a() = 0;
};
struct B : public iface {
virtual void do_a() override {}
};
template <typename T>
struct A {
T value;
};
template <std::derived_from<iface> T>
void call_iface(A<T> &some_a) {
some_a.value.do_a();
}
int main() {
A<B> a {};
call_iface(a);
// This won't compile
// A<int> v {};
// call_iface(v);
return 0;
}
使用概念,您可以对函数和模板参数设置约束。仅当是 的基类std::derived_from<Derived, Base>
时才解析为真。Base
Derived
这基本上形式化了在旧 C++ 版本中使用普通 SFINAE 可以完成的工作。例如,可以使用 C++11 实现类似的结果std::enable_if
:
#include <type_traits>
struct iface {
virtual void do_a() = 0;
};
struct B : public iface {
virtual void do_a() override {}
};
template <typename T>
struct A {
T value;
};
template <typename T, typename = typename std::enable_if<std::is_base_of<iface, T>::value>::type>
void call_iface(A<T> &some_a) {
some_a.value.do_a();
}
int main() {
A<B> a {};
call_iface(a);
// This won't compile
// A<int> v {};
// call_iface(v);
return 0;
}
SFINAE 是一个巧妙的 hack,它滥用了在 C++ 中失败的模板替换会导致它被忽略而不是导致错误这一事实。此模式已被 C++11 中的标准识别并由 instd::enable_if
形式化<type_traits>
。
编辑:请注意,在此示例中,我没有准确描述您的用例(即A 的任何子类,只要它也实现 ISomeInterface),但通过组合需求很容易适应。
例如,您的用例可以这样表示:
#include <concepts>
struct A {};
struct iface {
virtual void do_a() = 0;
};
struct B : public A, public iface {
virtual void do_a() override {}
};
struct C : public A {};
template <typename T>
requires std::derived_from<T, A> && std::derived_from<T, iface>
void call_iface(T &both) {}
int main() {
B b {};
call_iface(b);
// This won't compile
// C v {};
// call_iface(v);
return 0;
}
推荐阅读
- email - Gmail Mobile 不尊重图像样式“最大宽度:100%”
- c++ - 缓冲的 MySql 连接器 C++ 结果集
- php - 在 readfile() 之后替换输出缓冲区
- c# - 如何在没有凭据的情况下在 C# 中访问 Google Drive 共享内容
- javascript - React.js 没有呈现正确的字体真棒图标
- javascript - 在 Javascript 和/或 jQuery 中,如何在包装的 div 中获取第一行文本
- documentum - 连接到文档源时出错
- javascript - 如何使用 moment.js 获得最后完成的 15 分钟?
- sql - 取消选择在此查询中不起作用
- webpack - “PageSpeed Insights”不显示外部文件?