Skip to content

Instantly share code, notes, and snippets.

@stiff
Last active September 26, 2021 15:25
Show Gist options
  • Save stiff/27607ddeb4da590d915423ba6779f18e to your computer and use it in GitHub Desktop.
Save stiff/27607ddeb4da590d915423ba6779f18e to your computer and use it in GitHub Desktop.
Type level routes in C++20
// 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