C++ - 如何判断一个类型/类是否嵌套?

6
在看到许多关于C++元编程的例子后,可以确定类的许多属性(例如知道类型是否是模板的特化),或者知道一个类是否包含给定的嵌套类型; 但我想知道是否可能编写一个测试或特性,以确定最后一个的反向-检查给定的Type是否嵌套在classstruct中。

换句话说,我正在寻找以下伪代码的等效物:

template <typename Type> struct is_nested {
    enum { value = {__some magic__} };
};

typedef int type1;
struct Something { typedef int internal_type; };
typedef Something::internal_type type2;

//...later, likely at a different scope

is_nested< int >::value; // yields false
is_nested< std::vector<int>::iterator >::value; // yields true
is_nested< type1 >::value; // yields false
is_nested< type2 >::value; // yields true

我知道可以使用 sizeof 来实现是/否测试,而且我认为 Type 是这些测试的一部分,但我无法弄清楚如何将某种“任何可行类型”插入到测试中,以便我可以形成像 Anytype::Type 这样的表达式。

template 
struct is_nested
{
    typedef char yes;
    typedef struct { char u[2]; } no;
// Herein lies the problem ???? static yes test( char [ sizeof(Anytype::Type) ] ) ; ???? static no test(...);
public: enum { value = sizeof(test(0)) == sizeof(char) }; };

(请注意,我不关心也不知道 什么 类型会嵌套在 Type 中;所有这些都只与 Type 有关。换句话说,此特性应该仅依赖于 Type。)

我正在寻找一个 C++ 解决方案,无论是在 C++11 还是 C++03 中,但在第一种情况下,如果可以回溯使用,则更加欢迎。


1
这个问题的目的是解决什么问题? - Pete Becker
我主要在理论上探讨如何改进我对C++03中类型安全枚举的适应,通过禁用嵌套在结构体内部的enum的关系运算符来解决这个问题是我正在研究的两种方法之一。 - Luis Machuca
2个回答

1
可能可以使用编译器的非标准功能来检查“规范类型”(在解析所有别名后的结果类型)是否嵌套。 CTTI 可以在编译时获取类型名称。然后在字符串中找到:
#include <vector>
#include "ctti/type_id.hpp"

constexpr bool has_colon(const ctti::detail::string& s, size_t i) {
    return i < s.length() ? (s[i] == ':' || has_colon(s, i + 1)) : false;
}

template<typename T>
using is_nested = integral_constant<bool, has_colon(ctti::type_id<T>().name(), 0)>;

typedef int type1;
struct Something { typedef int internal_type; };
typedef Something::internal_type type2;

static_assert(!is_nested< int >::value, "");
static_assert(is_nested< std::vector<int>::iterator >::value, "");
static_assert(!is_nested< type1 >::value, "");
// static_assert(is_nested< type2 >::value, ""); // fail

第四个检查将失败,因为type2只是int,并没有嵌套。

1
你所要求的不可能,但并不是因为技术上的限制,而是因为你无法总是确定类型名称是否标识了嵌套类型 - 而模板使用的是类型,而不是名称。
例如,在这种情况下:
is_nested< std::vector<int>::iterator >::value

您不知道什么是iterator。考虑这个类my_vector

template<typename T>
struct my_vector
{
    typedef T* iterator;
    // ...
};

我应该得到什么结果才能得知is_nested<my_vector<int>::iterator>::value的值?你可能期望结果为true

然而,这里嵌套的是别名,而不是类型本身:类型int*并没有被嵌套。实际上,我相信你希望以下内容返回false

is_nested<int*>::value

所以在这里,相同的is_nested<T>特性应该会给出两个不同的结果,即使是相同的类型T(在这种情况下是int*)。基于is_nested<>定义value的信息无法从类型T本身中获取 - 并且模板使用的是类型,而不是名称。

在指针作为迭代器和其他类似情况可能出现的问题上,您提出了一个很好的观点。不过,在这种情况下,我希望编译器能够解决它,因为迭代器类型是已知的;在这种情况下,例如,这个特性将有助于确定容器类型是否具有连续存储(如果迭代器类型是原始指针,则肯定会产生“false”,否则可能会产生“true”)。 - Luis Machuca
@LuisMachuca:不确定你说“解决”时是什么意思。你所说的“它”是什么意思?你的is_nested<>特性将获得一个输入类型,这两种情况下都是int *。这就是is_nested<>所知道的一切。没有办法编写is_nested<>以在给定相同模板参数的情况下产生不同的结果。 - Andy Prowl
真的,不幸的是。这意味着我必须放弃这种方法。 - Luis Machuca
@LuisMachuca:我很遗憾 :( - Andy Prowl
在这一点上,我应该问什么是正确的协议?问题是否标记为已回答但未解决,总体关闭,还是...? - Luis Machuca

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