Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/136.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何在编译时对类型排序?_C++_Types_Tuples_Template Meta Programming_C++17 - Fatal编程技术网

C++ 如何在编译时对类型排序?

C++ 如何在编译时对类型排序?,c++,types,tuples,template-meta-programming,c++17,C++,Types,Tuples,Template Meta Programming,C++17,考虑以下计划: #include <tuple> #include <vector> #include <iostream> #include <type_traits> template <class T> struct ordered {}; template <class... T> struct ordered<std::tuple<T...>> { using type = /*

考虑以下计划:

#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;
}
#包括
#包括
#包括
#包括
模板
结构有序{};
模板
结构有序
{
使用type=/*重新排序的元组*/;
};
模板
使用ordered_t=typename ordered::type;
int main(int argc,char*argv[])
{
使用type1=std::tuple;
使用type2=std::tuple;

std::cout最难的部分是找到一种对类型进行排序的方法。通过谓词对类型列表进行排序是一件麻烦事,但也是可行的。我将在这里重点介绍比较谓词

一种方法是创建一个类模板,该模板为每种类型定义一个唯一的id。这样做可以使比较器易于编写:

template <typename T, typename U>
constexpr bool cmp() { return unique_id_v<T> < unique_id_v<U>; }
然后gcc将
cmp
报告为
“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;
}
constexpr size\u t cstrlen(const char*p){
尺寸长度=0;
而(*p){
++len;
++p;
}
回程透镜;
}
模板
constexpr bool cmp(){
const char*pf=\uuuu PRETTY\u FUNCTION\uuuuuu;
常量字符*a=pf+
#如果有声音__
cstrlen(“bool cmp()[T=”)
#否则
cstrlen(“constexpr bool cmp()[with T=”)
#恩迪夫
;
常量字符*b=a+1;
#如果有声音__
而(*b!=',')++b;
#否则
而(*b!=';')++b;
#恩迪夫
尺寸a_len=b-a;
b+=cstrlen(“;U=”);
常量字符*end=b+1;
而(*end!=']')++end;
尺寸b_len=end-b;
对于(大小i=0;i
通过一些测试:

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>>());
static_断言(cmp());
静态断言(!cmp());
静态断言(!cmp());
静态断言(!cmp());
静态_断言(cmp());

它不是最漂亮的实现,我也不确定它是否得到了标准的认可,但它允许您编写排序,而无需手动仔细注册所有类型。它在和上编译。因此,它可能已经足够好了。

这是对Barry提出的方法的一个轻微修改,该方法适用于Visual StudioStudio。而不是创建存储函数名称的编译时字符串:

template <typename T, typename U>
constexpr bool cmp() 
模板
constexpr bool cmp()
此方法直接比较由type\U name:name()返回的两种类型的名称。当宏\uu PRETTY\U FUNCTION\uuuu返回的类型T和U的名称用逗号分隔时,Barry的方法不起作用,因为当T或U是类或函数模板时,逗号也可以分隔模板参数

// length of null-terminated string
constexpr size_t cstrlen(const char* p) 
{
    size_t len = 0;
    while (*p) 
    {
        ++len;
        ++p;
    }

    return len;
}

// constexpr string representing type name
template<class T>
struct type_name
{
    static constexpr const char* name() 
    { 
        #if defined (_MSC_VER)
            return __FUNCSIG__; 
        #else
            return __PRETTY_FUNCTION__;
        #endif
    };
};

// comparison of types based on type names
template<class T1, class T2>
constexpr bool less()
{
    const char* A   = type_name<T1>::name();
    const char* B   = type_name<T2>::name();

    size_t a_len    = cstrlen(A);
    size_t b_len    = cstrlen(B);

    size_t ab_len   = (a_len < b_len) ? a_len : b_len;

    for (size_t i = 0; i < ab_len; ++i) 
    {
        if (A[i] != B[i]) 
            return A[i] < B[i];
    }

    return a_len < b_len;
}

// simple checks
template<class ... Type>
struct list;

static_assert(less<list<int, void, list<void, int>>, list<int, void, list<void, void>>>());
static_assert(less<list<int, void, list<void, int>>, list<int, void, list<void, int>, int>>());
//以null结尾的字符串的长度
constexpr size\u t cstrlen(const char*p)
{
尺寸长度=0;
而(*p)
{
++len;
++p;
}
回程透镜;
}
//表示类型名称的constexpr字符串
模板
结构类型名称
{
静态constexpr const char*name()
{ 
#如果已定义(\u MSC\u VER)
返回函数;
#否则
返回函数;
#恩迪夫
};
};
//基于类型名的类型比较
模板
constexpr bool less()
{
const char*A=type_name::name();
const char*B=type_name::name();
尺寸a长度=cstrlen(a);
尺寸b_len=cstrlen(b);
大小为(a_len
此方法适用于VS。我不确定它是否适用于Clang或GCC。

tl;dr:在编译时获取类型名称,并按其排序。 在我看来,以前的答案有点特殊——至少在实现上是这样

在这一点上,我们有一个非常好的多编译器支持,用于获取类型名称作为编译时字符串,作为字符串视图。我在这里只引用它的签名:

template <typename T>
constexpr std::string_view type_name();
模板
constexpr std::string_视图类型_name();

这构成了从类型到编译时可比较值的内射映射。给定这些值,您可以轻松实现一个类似过程来获取每个类型的相对顺序。最后,您可以使用这些顺序组装一个新元组。

可能吗?是的。无论您得到什么答案,Andrei Alexandrescu都在“现代C++设计”的方式回到2001。细节无疑会有所不同,但核心思想是相同的。@ StayytLe:如果是什么,代码> T!= T2< /代码>但是<代码> siZeof(T1)= sisiof(T2)
?您将如何对它们进行唯一排序,以使
std::is_same
按预期工作?@Nawaz-处理任何其他类型数据的方法相同。如果库不能,则强制用户提供任意排序。这不是不可能的。可以像添加一个或两个模板专门化一样简单。@StoryTeller:这就可以实现算法对于一个怪物,因为它很难提供模板特化,或者对于每一对大小相等的这样的对,那么问题是,为什么人们会使用这样的Meta FAN来开始?为什么不手动地这样做?在这个区域中似乎缺少C++。在编译时应该有一种排序类型的方法。编译时间O。运算符,相当于类型的
std::less
。@Vincent:这整个问题可能是XY问题吗?如果您只需要比较两个元组的等价性,那么可能就不需要对它们进行排序-使用类型别名技术进行搜索,即使n^2可能比排序两个集合和compa更快在
boost::hana
中,类型的表示是相等的
static_断言(boost::hana::type_c==boost::hana::type_c);
template <typename T>
constexpr std::string_view type_name();