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>>>::AType是void或其他东西(它无法编译)
我怎样才能做到这一点?
我的精确用例是: 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)
请注意,模板由我们的概念保护。