gpt4 book ai didi

c++ - 如何在编译时订购类型?

转载 作者:IT老高 更新时间:2023-10-28 22:37:24 24 4
gpt4 key购买 nike

考虑以下程序:

#include <tuple>
#include <vector>
#include <iostream>
#include <type_traits>

template <class T>
struct ordered {};

template <class... T>
struct ordered<std::tuple<T...>>
{
using type = /* a reordered tuple */;
};

template <class T>
using ordered_t = typename ordered<T>::type;

int main(int argc, char* argv[])
{
using type1 = std::tuple<char, std::vector<int>, double>;
using type2 = std::tuple<std::vector<int>, double, char>;
std::cout << std::is_same_v<type1, type2> << "\n"; // 0
std::cout << std::is_same_v<ordered_t<type1>, ordered_t<type2>> << "\n"; // 1
return 0;
}

ordered 帮助器必须对元组中的类型进行重新排序,以便具有相同类型但排序不同的两个元组导致相同的元组类型:可以是第一个,第二个,甚至是另一个:它只需要具有相同的大小和相同的元素,但顺序是唯一的(不管这个顺序如何)。

是否可以在编译时使用模板元编程技术做到这一点?

最佳答案

困难的部分是想出一种订购类型的方法。按谓词对类型列表进行排序是一件苦差事,但也是可行的。我将在这里只关注比较谓词。

一种方法是创建一个类模板,为每种类型定义一个唯一的 id。这很有效,并且可以轻松编写比较器:

template <typename T, typename U>
constexpr bool cmp() { return unique_id_v<T> < unique_id_v<U>; }

但是想出这些唯一的 ID 是一个不一定可行的障碍。您是否将它们全部注册在一个文件中?这不能很好地扩展。

如果我们可以...得到所有类型的名称作为编译时字符串,那就太好了。反射(reflection)会给我们这个,然后这个问题是微不足道的。在那之前,我们可以做一些更脏的事情:使用 __PRETTY_FUNCTION__ . gcc 和 clang 都可以在 constexpr 中使用该宏。上下文,尽管它们对此字符串有不同的格式。如果我们有这样的签名:

template <typename T, typename U>
constexpr bool cmp();

然后 gcc 报告 cmp<char, int>作为 "constexpr bool cmp() [with T = char; U = int]"而 clang 将其报告为 "bool cmp() [T = char, U = int]" .它是不同的......但足够接近我们可以使用相同的算法。基本上是:找出 T 的位置和 U在那里,只是做正常的字符串字典比较:

constexpr size_t cstrlen(const char* p) {
size_t len = 0;
while (*p) {
++len;
++p;
}
return len;
}

template <typename T, typename U>
constexpr bool cmp() {
const char* pf = __PRETTY_FUNCTION__;
const char* a = pf +
#ifdef __clang__
cstrlen("bool cmp() [T = ")
#else
cstrlen("constexpr bool cmp() [with T = ")
#endif
;

const char* b = a + 1;
#ifdef __clang__
while (*b != ',') ++b;
#else
while (*b != ';') ++b;
#endif
size_t a_len = b - a;
b += cstrlen("; U = ");
const char* end = b + 1;
while (*end != ']') ++end;
size_t b_len = end - b;

for (size_t i = 0; i < std::min(a_len, b_len); ++i) {
if (a[i] != b[i]) return a[i] < b[i];
}

return a_len < b_len;
}

通过一些测试:

static_assert(cmp<char, int>());
static_assert(!cmp<int, char>());
static_assert(!cmp<int, int>());
static_assert(!cmp<char, char>());
static_assert(cmp<int, std::vector<int>>());

这不是最漂亮的实现,我不确定它是否受到标准的有意义的认可,但它可以让您编写您的排序,而无需手动和仔细地注册所有类型。它在 clang 上编译和 gcc .所以也许它已经足够好了。

关于c++ - 如何在编译时订购类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48723974/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com