扩展两个类的参数的语法

Syntax of a parameter extending two classes

本文关键字:参数 语法 两个 扩展      更新时间:2023-10-16

在Java中,可以声明一个参数实现多个接口。你必须使用泛型语法,但你可以:

public <T extends Appendable & Closeable> void spew(T t) {
    t.append("Bleah!n");
    if (timeToClose())
        t.close();
}

在C++中,一种常见的模式是使用只包含纯虚拟函数的类作为接口:

class IAppendable {
public:
    virtual void append(const std::string&) = 0;
};
class ICloseable {
public:
    virtual void close() = 0;
};

编写一个接受ICloseable的函数是很琐碎的(这只是多态性):

void closeThis(ICloseable&);

但是,采用参数的函数的签名是什么呢?该参数在Java示例中从ICloseableIAppendable继承而来?

以下是如何仅使用标准设施编写它:

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();
}

在Coliru 上直播

如果有更多的基类,我建议制定一个更简洁的类型特征,在enable_if:中检查它们

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();
}

@Quentin的出色回答促使我编写了一个通用的可变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
    >
{};

第一个模板参数是要检查的类型,其余参数是第一个类型必须继承的类型。

例如,

class A {};
class B {};
class C {};
template<class T>
std::enable_if_t<
    inherits<T, A, B, C>{},
    void
> foo(const T& t)
{
    // ...
}

这里,作为参数传递给foo的任何类型的T都必须继承自ABC

在Coliru 上直播