检查 class 是否明确定义了继承层次结构中的成员类型
Check if a class explicitely defines a member type in an inheritance hierarchy
我有一组 classes,它们使用成员 typedef Next
链接起来,如下所示:
class Y; class Z;
class X { public: typedef Y Next; };
class Y { public: typedef Z Next; };
class Z { };
我需要一种方法来获取链的最终 class,从链的任何 class 开始。感谢accepted answer of this post,我写了下面的代码:
// cond_type<Condition, Then, Else>::type // selects type 'Then' if 'Condition' is true, or type 'Else' otherwise
template <bool Condition, typename Then, typename Else = void>
struct cond_type
{
typedef Then type;
};
template <typename Then, typename Else>
struct cond_type<false, Then, Else >
{
typedef Else type;
};
template <class C, typename _ = void>
struct chain
{
typedef C last;
};
template <class C>
struct chain<C, typename cond_type<false, typename C::Next>::type>
{
typedef typename chain<typename C::Next>::last last;
};
使用上面的模板 chain<C>::last
,下面的代码正确实例化了 class Z
的 3 个对象,正如预期的那样:
chain<X>::last z1;
chain<Y>::last z2;
chain<Z>::last z3;
但是,如果所考虑的 classes 集合形成继承层次结构,则按以下方式:
class U; class V;
class T { public: typedef U Next; };
class U : public T { public: typedef V Next; };
class V : public U { };
然后,使用模板 chain<C>::last
,使用上述集合中的任何 class C
,例如:
chain<T>::last v;
导致以下编译错误:
1>test.cpp(88): error C3646: 'last' : unknown override specifier
我理解问题是classV
继承自父classU
中定义的typedef V Next
,导致编译专门模板 chain<V,V>
的形式,而应该使用通用模板,因为 V
没有成员 Next
.
无论如何,我被困在这里,因为我需要一种有效的机制,即使在 class 层次结构的情况下也是如此。
我该怎么做?
PS:class之间的继承必须保持public;成员类型定义必须保持 public.
就这么简单:
template <typename T, typename = void> struct last_t_impl
{
using type = T;
};
template <typename T> struct last_t_impl
<T, std::enable_if_t<!std::is_same_v<typename T::Next, T>>>
{
using type = typename last_t_impl<typename T::Next>::type;
};
template <typename T> using last_t = typename last_t_impl<T>::type;
用法:
last_t<T> v1;
last_t<U> v2;
last_t<V> v3;
如果您需要以上代码为 C++14(而不是 C++17)编译,请将 std::is_same_v<A,B>
更改为 std::is_same<A,B>::value
。
请注意,您的 typename cond_type<false, T>::type
可以替换为 std::void_t<T>
(或 C++14 中的 std::conditional_t<false,T,void>
)。但在这种情况下不需要,因为链的末端将由 std::is_same_v<typename T::Next, T>
检测到 SFINAE。 (即使 T::Next
由于某种原因不存在,SFINAE 仍会启动并且 last_t<T>
将只是 T
。)
类型链接的 classes 应该作为与您的 class 层次结构分开的抽象来实现。
#include <iostream>
#include <string>
#include <type_traits>
// Definitions for TypeChain as an abstraction
// Simple interface to declare next class for a class.
template <typename N>
struct Next {
using next = N;
};
// Primary template for a type chain.
template <typename T>
struct TypeChain : Next<void>{};
/// Implementation of type-function last.
template <typename T, typename C = typename TypeChain<T>::next> struct last_t_impl
{
using type = std::conditional_t<std::is_same_v<C, void>, T, typename last_t_impl<C>::type>;
};
// Never used, but needed to end recursion.
template <> struct last_t_impl<void, void>
{
using type = void;
};
template <typename T> using last_t = typename last_t_impl<T>::type;
// Définition of the class hierarchy, without chaining.
class T { };
class U : public T { };
class V : public U { };
// Definition of the chain.
// T => U => V
// Specialisation of TypeChain for T
template<>
struct TypeChain<T> : Next<U> {};
// Specialisation of TypeChain for U
template<>
struct TypeChain<U> : Next<V>{};
// No specialisation for V, since it has no next value.
// Test (should run three 1)
int main()
{
std::cout << std::is_same_v<last_t<T>, V> << "\n";
std::cout << std::is_same_v<last_t<U>, V> << "\n";
std::cout << std::is_same_v<last_t<V>, V> << "\n";
}
它无法检测到链循环,但此实现将两个抽象(class 层次结构和类型链)保留为单独的概念,因此您可以在不修改 [=15] 的情况下提供这些功能=] 层次结构,在我看来更好。
我有一组 classes,它们使用成员 typedef Next
链接起来,如下所示:
class Y; class Z;
class X { public: typedef Y Next; };
class Y { public: typedef Z Next; };
class Z { };
我需要一种方法来获取链的最终 class,从链的任何 class 开始。感谢accepted answer of this post,我写了下面的代码:
// cond_type<Condition, Then, Else>::type // selects type 'Then' if 'Condition' is true, or type 'Else' otherwise
template <bool Condition, typename Then, typename Else = void>
struct cond_type
{
typedef Then type;
};
template <typename Then, typename Else>
struct cond_type<false, Then, Else >
{
typedef Else type;
};
template <class C, typename _ = void>
struct chain
{
typedef C last;
};
template <class C>
struct chain<C, typename cond_type<false, typename C::Next>::type>
{
typedef typename chain<typename C::Next>::last last;
};
使用上面的模板 chain<C>::last
,下面的代码正确实例化了 class Z
的 3 个对象,正如预期的那样:
chain<X>::last z1;
chain<Y>::last z2;
chain<Z>::last z3;
但是,如果所考虑的 classes 集合形成继承层次结构,则按以下方式:
class U; class V;
class T { public: typedef U Next; };
class U : public T { public: typedef V Next; };
class V : public U { };
然后,使用模板 chain<C>::last
,使用上述集合中的任何 class C
,例如:
chain<T>::last v;
导致以下编译错误:
1>test.cpp(88): error C3646: 'last' : unknown override specifier
我理解问题是classV
继承自父classU
中定义的typedef V Next
,导致编译专门模板 chain<V,V>
的形式,而应该使用通用模板,因为 V
没有成员 Next
.
无论如何,我被困在这里,因为我需要一种有效的机制,即使在 class 层次结构的情况下也是如此。
我该怎么做?
PS:class之间的继承必须保持public;成员类型定义必须保持 public.
就这么简单:
template <typename T, typename = void> struct last_t_impl
{
using type = T;
};
template <typename T> struct last_t_impl
<T, std::enable_if_t<!std::is_same_v<typename T::Next, T>>>
{
using type = typename last_t_impl<typename T::Next>::type;
};
template <typename T> using last_t = typename last_t_impl<T>::type;
用法:
last_t<T> v1;
last_t<U> v2;
last_t<V> v3;
如果您需要以上代码为 C++14(而不是 C++17)编译,请将 std::is_same_v<A,B>
更改为 std::is_same<A,B>::value
。
请注意,您的 typename cond_type<false, T>::type
可以替换为 std::void_t<T>
(或 C++14 中的 std::conditional_t<false,T,void>
)。但在这种情况下不需要,因为链的末端将由 std::is_same_v<typename T::Next, T>
检测到 SFINAE。 (即使 T::Next
由于某种原因不存在,SFINAE 仍会启动并且 last_t<T>
将只是 T
。)
类型链接的 classes 应该作为与您的 class 层次结构分开的抽象来实现。
#include <iostream>
#include <string>
#include <type_traits>
// Definitions for TypeChain as an abstraction
// Simple interface to declare next class for a class.
template <typename N>
struct Next {
using next = N;
};
// Primary template for a type chain.
template <typename T>
struct TypeChain : Next<void>{};
/// Implementation of type-function last.
template <typename T, typename C = typename TypeChain<T>::next> struct last_t_impl
{
using type = std::conditional_t<std::is_same_v<C, void>, T, typename last_t_impl<C>::type>;
};
// Never used, but needed to end recursion.
template <> struct last_t_impl<void, void>
{
using type = void;
};
template <typename T> using last_t = typename last_t_impl<T>::type;
// Définition of the class hierarchy, without chaining.
class T { };
class U : public T { };
class V : public U { };
// Definition of the chain.
// T => U => V
// Specialisation of TypeChain for T
template<>
struct TypeChain<T> : Next<U> {};
// Specialisation of TypeChain for U
template<>
struct TypeChain<U> : Next<V>{};
// No specialisation for V, since it has no next value.
// Test (should run three 1)
int main()
{
std::cout << std::is_same_v<last_t<T>, V> << "\n";
std::cout << std::is_same_v<last_t<U>, V> << "\n";
std::cout << std::is_same_v<last_t<V>, V> << "\n";
}
它无法检测到链循环,但此实现将两个抽象(class 层次结构和类型链)保留为单独的概念,因此您可以在不修改 [=15] 的情况下提供这些功能=] 层次结构,在我看来更好。