How to order types at compile-time?

Vincent

Consider the following program:

#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;
}

The ordered helper has to reorder types in a tuple, such that two tuples with the sames types, but ordered differently lead to the same tuple type: which can be the first one, the second one, or even another one: it just has to have the same size, and the same elements but in a unique order (regardless of this order).

Is it possible to do this at compile-time using template metaprogramming techniques?

Barry

The hard part is coming up with a way to order types. Sorting a type list by a predicate is a chore, but is doable. I'll focus here on just the comparison predicate.

One way is to just create a class template that defines a unique id for each type. That works and makes for an easy comparator to write:

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

But coming up with these unique ids is a hurdle that isn't necessarily feasible. Do you register them all in one file? That doesn't scale super well.

What would be great is if we could just... get the names of all the types as compile time strings. Reflection will give us that, and then this problem is trivial. Until then, we could do something slightly more dirty: use __PRETTY_FUNCTION__. Both gcc and clang are okay with using that macro in a constexpr context, although they have different formats for this string. If we have a signature like:

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

Then gcc reports cmp<char, int> as "constexpr bool cmp() [with T = char; U = int]" while clang reports it as "bool cmp() [T = char, U = int]". It's different... but close enough that we can use the same algorithm. Which is basically: figure out where T and U are in there and just do normal string lexicographic comparison:

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;
}

with some tests:

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>>());

It's not the prettiest implementation, and I'm not sure it's meaningfully sanctioned by the standard, but it lets you write your sort without having to manually and carefully register all your types. And it compiles on clang and gcc. So maybe it's good enough.

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

How to create compile time check for multiple C++ types?

分類Dev

Differentiating alias and real-types at compile time?

分類Dev

How is a vptr initialized at compile time?

分類Dev

How to enforce that a type implements a trait at compile time?

分類Dev

how to check the size of an array during compile time

分類Dev

How to tell if expression is evaluated at compile time or runtime?

分類Dev

How to check at compile time if type is polymorhic

分類Dev

How to ensure compile-time safety in custom data structures

分類Dev

How can you compare two character strings statically at compile time

分類Dev

How to get compile time error checking with real valued function arguments?

分類Dev

How can I use std::make_tuple at compile time?

分類Dev

How to create compile-time constant in Kotlin from enum?

分類Dev

How to use GenericArray with a limited range of length that can be detected at compile time?

分類Dev

How to use GenericArray with a limited range of length that can be detected at compile time?

分類Dev

How to list dynamic and Compile-time variables in Raku

分類Dev

How to use the program's exit status at compile time?

分類Dev

Implicit conversion at compile time

分類Dev

Compile time hash with constexpr

分類Dev

How to run two lists of tasks with different return types at the same time

分類Dev

How do nested variable types change time complexity?

分類Dev

How do I construct and compile this C# Expression with Generic types & lambda

分類Dev

Oracle and React: How to keep order for next time page loads

分類Dev

Execute compile time-compiled regex at compile time

分類Dev

webpack is compile time is very slow

分類Dev

Set Attribute Value at Compile Time

分類Dev

Finding duplicates in array at compile time

分類Dev

Compile time sort of heterogenous tuples

分類Dev

JSF El executing at compile time

分類Dev

c++ compile time error

Related 関連記事

  1. 1

    How to create compile time check for multiple C++ types?

  2. 2

    Differentiating alias and real-types at compile time?

  3. 3

    How is a vptr initialized at compile time?

  4. 4

    How to enforce that a type implements a trait at compile time?

  5. 5

    how to check the size of an array during compile time

  6. 6

    How to tell if expression is evaluated at compile time or runtime?

  7. 7

    How to check at compile time if type is polymorhic

  8. 8

    How to ensure compile-time safety in custom data structures

  9. 9

    How can you compare two character strings statically at compile time

  10. 10

    How to get compile time error checking with real valued function arguments?

  11. 11

    How can I use std::make_tuple at compile time?

  12. 12

    How to create compile-time constant in Kotlin from enum?

  13. 13

    How to use GenericArray with a limited range of length that can be detected at compile time?

  14. 14

    How to use GenericArray with a limited range of length that can be detected at compile time?

  15. 15

    How to list dynamic and Compile-time variables in Raku

  16. 16

    How to use the program's exit status at compile time?

  17. 17

    Implicit conversion at compile time

  18. 18

    Compile time hash with constexpr

  19. 19

    How to run two lists of tasks with different return types at the same time

  20. 20

    How do nested variable types change time complexity?

  21. 21

    How do I construct and compile this C# Expression with Generic types & lambda

  22. 22

    Oracle and React: How to keep order for next time page loads

  23. 23

    Execute compile time-compiled regex at compile time

  24. 24

    webpack is compile time is very slow

  25. 25

    Set Attribute Value at Compile Time

  26. 26

    Finding duplicates in array at compile time

  27. 27

    Compile time sort of heterogenous tuples

  28. 28

    JSF El executing at compile time

  29. 29

    c++ compile time error

ホットタグ

アーカイブ