参数包感知的std::is_base_of()

10

是否有可能在模板参数中提供的类型实现了参数包中列出的所有类型,即针对参数包使用std::is_base_of()函数时进行静态断言?

template <typename Type, typename... Requirements>
class CommonBase
{
    static_assert(is_base_of<Requirements..., Type>::value, "Invalid.");
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            parameter pack aware version of std::is_base_of()
public:
    template <typename T> T* as()
    {
        static_assert(std::is_base_of<Requirements..., T>::value, "Invalid.");
        return reinterpret_cast<T*>(this);
    }
};

我怀疑这是否可能。另外,你的第一个 is_base_of<Requirements...>::value 没有提到第二个参数。 - iammilind
static_assertion 是编译时的过程(参见这里)。编译器会在编译时检查 is_base_of 的值吗? - Amir Naghizadeh
1
当然会,因为is_base_of本身就是一个模板,而模板在编译时被实例化。 - Arne Mertz
2个回答

18

C++17更新: 使用C++17的折叠表达式,这几乎变得非常简单:

template <typename Type, typename... Requirements>
class CommonBase
{
    static_assert((std::is_base_of_v<Type, Requirements> && ...), "Invalid.");
};

你可以使用展开语法和一些静态版本的std::all_of来实现(C++11/14):
template <bool... b> struct static_all_of;

//implementation: recurse, if the first argument is true
template <bool... tail> 
struct static_all_of<true, tail...> : static_all_of<tail...> {};

//end recursion if first argument is false - 
template <bool... tail> 
struct static_all_of<false, tail...> : std::false_type {};

// - or if no more arguments
template <> struct static_all_of<> : std::true_type {};

template <typename Type, typename... Requirements>
class CommonBase
{
    static_assert(static_all_of<std::is_base_of<Type, Requirements>::value...>::value, "Invalid.");
    //                                               pack expansion:      ^^^
};

struct Base {};
struct Derived1 : Base {};
struct Derived2 : Base {};
struct NotDerived {};

int main()
{
  CommonBase <Base, Derived1, Derived2> ok;
  CommonBase <Base, Derived1, NotDerived, Derived2> error;
}

打包展开会扩展为在Requirements...中插入每种类型以获取std::is_base_of<Type, ?>::value的问号所得到的值列表。也就是说,对于main函数中的第一行,它将扩展为static_all_of<true, true>,对于第二行,则为static_all_of<true, false, true>。

我认为需要括号 static_assert((std::is_base_of_v<Type, Requirements> && ...), "Invalid."); - Tarquiscani
1
我指的是“C++17更新”代码中,而不是原始答案。 - Tarquiscani
@Tarquiscani 不好意思,现在已经修复了。(并且我学到了 MSVC 无论如何都不会编译它) - Arne Mertz
我遇到了相同的错误。幸运的是,它将在MSVC 16.0中得到修复。 - Tarquiscani
在C++17中,使用“conjunction”可能比折叠表达式更好,以避免不必要的实例化。 - L. F.
根据cppreference.com中的分类,这个折叠表达式属于哪个类别(一元左折叠、一元右折叠,...)? - Vishal Subramanyam

4

作为以后的参考,因为我刚遇到了这个问题,使用C++17现在您可以像这样使用fold表达式:

template<typename Base, typename... Args>
constexpr auto all_base_of()
{
    return (std::is_base_of<Base, Args>::value && ...);
}

static_assert(all_base_of<Base, A, B, C>());

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接