如何有条件地获取具有多重继承的多个基类的模板类型

fro*_*nca 1 c++ templates template-meta-programming c++17 c++20

这不是链接的重复项

考虑以下代码:

#include <type_traits>

template <typename... Bases>
struct Overloads : public Bases... {};

template <typename T>
struct A {
  using AType = T;
};

template <typename T>
struct B {
  using BType = T;
};

template <typename T>
struct C {
  using CType = T;
};

template <typename OverloadsType>
struct Derived : public OverloadsType {
  
};

int main() {
    // OK
    static_assert(std::is_same_v<typename Derived<Overloads<A<int>, B<float>, C<char>>>::AType, int>);
    // OK
    static_assert(std::is_same_v<typename Derived<Overloads<A<int>, B<float>, C<char>>>::BType, float>);
    // OK
    static_assert(std::is_same_v<typename Derived<Overloads<A<int>, B<float>, C<char>>>::CType, char>);
    // ???
    static_assert(std::is_same_v<typename Derived<Overloads<B<float>, C<char>>>::AType, void>);
    
}
Run Code Online (Sandbox Code Playgroud)

演示:链接

对于最后一行,我需要检测它Derived<Overloads<B<float>, C<char>>>不是派生自A,所以我想要typename Derived<Overloads<B<float>, C<char>>>::ATypevoid或其他东西(它无法编译)

我怎样才能做到这一点?

Nic*_*las 6

我的精确用例是: 1. 确定 Derived 是否源自A<T>某些T. 2. 如果是这样,请找出T

有了 C++20 概念,这并不太困难。A<T>您需要一个作为参数的函数。不需要有函数定义;我们只是使用模板参数推导。它永远不会被称为:

template<typename T>
T getDerivedFromAType(A<T> const&); //Not implemented, since we will never call it.
Run Code Online (Sandbox Code Playgroud)

任何U适用的类型getDerivedFromAType(u)要么是其A<T>本身,要么是派生自的类型A<T>(当然是来自单个类型)。 A<T>所以我们可以从中构建一个概念:

template<typename U>
concept IsDerivedFromA = requires(U u)
{
  getDerivedFromAType(u);
};
Run Code Online (Sandbox Code Playgroud)

只要没有人编写过多的getDerivedFromAType,就可以了。该函数应该位于detail命名空间中,或者有其他东西让人们知道它是禁止使用的。

为了获得实际T使用的A......好吧,函数返回是有原因的T。我们只需要一个using计算函数调用的返回类型的语句:

template<IsDerivedFromA T>
using BaseAType = decltype(getDerivedFromAType(std::declval<T>()));
Run Code Online (Sandbox Code Playgroud)

请注意,模板由我们的概念保护。