Last active
April 14, 2023 18:56
-
-
Save VictorLaskin/83a008453a18083a3dbf to your computer and use it in GitHub Desktop.
Named tuple for C++
This file contains 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
// Named tuple for C++ | |
// Example code from http://vitiy.info/ | |
// Written by Victor Laskin ([email protected]) | |
// Parts of code were taken from: https://gist.github.com/Manu343726/081512c43814d098fe4b | |
namespace foonathan { | |
namespace string_id { | |
namespace detail | |
{ | |
using hash_type = std::uint64_t; | |
constexpr hash_type fnv_basis = 14695981039346656037ull; | |
constexpr hash_type fnv_prime = 109951162821ull; | |
// FNV-1a 64 bit hash | |
constexpr hash_type sid_hash(const char *str, hash_type hash = fnv_basis) noexcept | |
{ | |
return *str ? sid_hash(str + 1, (hash ^ *str) * fnv_prime) : hash; | |
} | |
} | |
} | |
} // foonathan::string_id::detail | |
namespace fn_detail { | |
/// Named parameter (could be empty!) | |
template <typename Hash, typename... Ts> | |
struct named_param : public std::tuple<std::decay_t<Ts>...> { | |
using hash = Hash; ///< key | |
named_param(Ts&&... ts) : std::tuple<std::decay_t<Ts>...>(std::forward<Ts>(ts)...){ }; ///< constructor | |
template <typename P> | |
named_param<Hash,P> operator=(P&& p){ return named_param<Hash,P>(std::forward<P>(p)); }; | |
}; | |
template <typename Hash> | |
using make_named_param = named_param<Hash>; | |
/// Named tuple is just tuple of named params | |
template <typename... Params> | |
struct named_tuple : public std::tuple<Params...> | |
{ | |
template <typename... Args> | |
named_tuple(Args&&... args) : std::tuple<Args...>(std::forward<Args>(args)...) {} | |
static const std::size_t error = -1; | |
template<std::size_t I = 0, typename Hash> | |
constexpr typename std::enable_if<I == sizeof...(Params), const std::size_t>::type | |
static get_element_index() | |
{ | |
return error; | |
} | |
template<std::size_t I = 0, typename Hash> | |
constexpr typename std::enable_if<I < sizeof...(Params), const std::size_t>::type | |
static get_element_index() | |
{ | |
using elementType = typename std::tuple_element<I, std::tuple<Params...>>::type; | |
//return (typeid(typename elementType::hash) == typeid(Hash)) ? I : get_element_index<I + 1, Hash>(); | |
return (std::is_same<typename elementType::hash, Hash>::value) ? I : get_element_index<I + 1, Hash>(); | |
} | |
template<typename Hash> | |
const auto& get() const | |
{ | |
constexpr std::size_t index = get_element_index<0, Hash>(); | |
static_assert((index != error), "Wrong named tuple key"); | |
auto& param = (std::get< index >(static_cast<const std::tuple<Params...>&>(*this))); | |
return std::get<0>( param ); | |
} | |
template<typename NP> | |
const auto& operator[](NP&& param) | |
{ | |
return get<typename NP::hash>(); | |
} | |
}; | |
} | |
template <typename... Args> | |
auto make_named_tuple(Args&&... args) | |
{ | |
return fn_detail::named_tuple<Args...>(std::forward<Args>(args)...); | |
} | |
#define param(x) fn_detail::make_named_param< std::integral_constant<foonathan::string_id::detail::hash_type, foonathan::string_id::detail::sid_hash(x)> >{} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment