Last active
September 26, 2021 15:25
-
-
Save stiff/27607ddeb4da590d915423ba6779f18e to your computer and use it in GitHub Desktop.
Type level routes in C++20
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// loosely based on https://servant.dev | |
// /usr/local/Cellar/gcc/10.2.0/bin/g++-10 -std=c++20 type-level-routes.cpp && ./a.out | |
#include <iostream> | |
#include <string> | |
// FixedString from https://www.reddit.com/r/cpp/comments/bhxx49/c20_string_literals_as_nontype_template/ | |
template<unsigned N> | |
struct FixedString { | |
char buf[N + 1]{}; | |
constexpr FixedString(char const* s) { | |
for (unsigned i = 0; i != N; ++i) buf[i] = s[i]; | |
} | |
constexpr operator char const*() const { return buf; } | |
}; | |
template<unsigned N> FixedString(char const (&)[N]) -> FixedString<N - 1>; | |
// own code | |
// Static url part | |
template <FixedString Path> | |
struct Slug { | |
static constexpr char const* path = Path; | |
}; | |
// Dynamic url part | |
template <typename Value> | |
struct Capture { | |
using value_t = Value; | |
}; | |
// Route | |
template <typename... Args> | |
struct Route; | |
template<typename ValueT, typename... Rest> | |
struct Route<Capture<ValueT>, Rest...> { | |
static std::string toString(ValueT value, auto... rest) { | |
return "/" + std::to_string(value) + Route<Rest...>::toString(rest...); | |
} | |
}; | |
template<typename SlugT, typename... Rest> | |
struct Route<SlugT, Rest...> { | |
static std::string toString(auto... rest) { | |
return "/" + std::string(SlugT::path) + Route<Rest...>::toString(rest...); | |
} | |
}; | |
template <> | |
struct Route<> { | |
static std::string toString() { | |
return ""; | |
} | |
}; | |
using BlogRoot = Route< Slug<"blog"> >; | |
using AllPosts = Route< Slug<"blog">, Slug<"posts"> >; | |
using SinglePost = Route< Slug<"blog">, Slug<"posts">, Capture<int> >; | |
int main() { | |
// /blog | |
std::cout << "blog = " << BlogRoot::toString() << std::endl; | |
// /blog/posts | |
std::cout << "allPosts = " << AllPosts::toString() << std::endl; | |
// invalid path, compilation error | |
// std::cout << "singlePost = " << SinglePost::toString() << std::endl; | |
// /blog/posts/42 | |
std::cout << "singlePost = " << SinglePost::toString(42) << std::endl; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment