C++ 扩展两个类的参数的语法
在Java中,一个参数可以实现多个接口。您必须使用泛型语法,但您可以:C++ 扩展两个类的参数的语法,c++,inheritance,C++,Inheritance,在Java中,一个参数可以实现多个接口。您必须使用泛型语法,但您可以: public <T extends Appendable & Closeable> void spew(T t) { t.append("Bleah!\n"); if (timeToClose()) t.close(); } 编写一个函数来获取一个ICloseable(这只是多态性): 但是一个函数的签名是什么,它采用了一个参数,如Java示例中所示,该参数继承自IClo
public <T extends Appendable & Closeable> void spew(T t) {
t.append("Bleah!\n");
if (timeToClose())
t.close();
}
编写一个函数来获取一个ICloseable
(这只是多态性):
但是一个函数的签名是什么,它采用了一个参数,如Java示例中所示,该参数继承自
ICloseable
和IAppendable
?以下是仅使用标准工具编写它的方法:
template <class T>
std::enable_if_t<
std::is_base_of<IAppendable, T>{} && std::is_base_of<ICloseable, T>{},
void
> closeThis(T &t) {
t.append("end");
t.close();
}
@昆汀出色的回答促使我编写了一个广义的、可变的
inherits
模板。它允许您轻松地指定任意数量的基类
#include <type_traits>
template<class... T> struct inherits :
std::true_type
{};
template<class T, class Base1, class... Bases>
struct inherits<T, Base1, Bases...> :
std::conditional_t< std::is_base_of<Base1, T>{},
inherits<T, Bases...>,
std::false_type
>
{};
#包括
模板结构继承:
std::真_类型
{};
模板
结构继承:
std::conditional_t
{};
第一个模板参数是要检查的类型,其余参数是第一个类型必须从中继承的类型
比如说,
class A {};
class B {};
class C {};
template<class T>
std::enable_if_t<
inherits<T, A, B, C>{},
void
> foo(const T& t)
{
// ...
}
A类{};
B类{};
C类{};
模板
std::如果启用,则启用<
继承{},
无效的
>foo(施工及测试)
{
// ...
}
在这里,作为参数传递给foo
的任何类型T
都必须继承自A
、B
和C
问题是:如何实现一个既源于
IAppendable
又源于ICloseable
的类?或者:如何创建模板化类/函数/etc。其typename T
参数必须同时包含IAppendable
和ICloseable
?后者(为了清晰起见,我进行了编辑)。实现一个同时实现两者的类很简单:class a:public-IAppendable,public-ICloseable{}代码>很有趣,谢谢!在返回类型上使用SFINAE是唯一的方法吗?(我感觉错误消息与实际的程序员错误并不相关。)@Thirty340我认为,当概念最终进入语言时,将有助于为这些需求定义更清晰的语法。现在,这是惯用的方式,非常友好。取消对One
行的注释将触发一条错误消息,其中包含candidate:template std::enable\u if\u t closeThis(t&)
。不太理想,但对于模板错误来说也不是那么糟糕;)我不确定is_base\u of
是正确的检查,因为它还检测不明确和不可访问的基。(当然,如果我们使用的是模板,我根本不明白为什么我们需要这些基类。)@t.C.我认为是可转换的,但这涵盖了不太有用的情况(赋值的左侧)和更模糊的情况(私下从接口继承??)。将函数限制为一组接口基本上会禁用duck类型,根据具体情况,duck类型可能过于自由。我为您的所有基础编写了一个可变实现,请参见我的答案。让我知道它是否可以改进。很好的实现:)另外,我是个傻瓜,错过了allTrue
函数的复制粘贴…谢谢!我以为你故意把它作为练习留给读者:D
constexpr bool allTrue() {
return true;
}
template <class... Bools>
constexpr bool allTrue(bool b1, Bools... bools) {
return b1 && allTrue(bools...);
}
template <class T, class... Bases>
struct all_bases {
static constexpr bool value = allTrue(std::is_base_of<Bases, T>{}...);
constexpr operator bool () const {
return value;
}
};
template <class T>
std::enable_if_t<
all_bases<T, IAppendable, ICloseable>{},
void
> closeThis(T &t) {
t.append("end");
t.close();
}
#include <type_traits>
template<class... T> struct inherits :
std::true_type
{};
template<class T, class Base1, class... Bases>
struct inherits<T, Base1, Bases...> :
std::conditional_t< std::is_base_of<Base1, T>{},
inherits<T, Bases...>,
std::false_type
>
{};
class A {};
class B {};
class C {};
template<class T>
std::enable_if_t<
inherits<T, A, B, C>{},
void
> foo(const T& t)
{
// ...
}