How can I achieve a compile-time index operation wrapped in an operator like () or []?
// works, I already made this
template<int i>
constexpr auto get() const
{
// implementation
// where i is used as a template parameter to other things
}
// no idea how to achieve this
template</*magic*/>
constexpr auto operator[](/*more magic*/) const
{
return get</*use magic*/>();
}
Usage
constexpr my_class x;
...= x.get<1>(); // works, kind of ugly
...= x[1]; // doesn't work, parameters aren't compiletime or something
Here's an example I slapped together. Hopefully the solution to this example will be the same solution to my real problem.
#include <tuple>
class c
{
std::tuple< int, float, char > tuple { 1, 2.f, 'c' };
public:
template< std::size_t i >
constexpr auto & get()
{
return std::get<i>(tuple);
}
//constexpr auto & operator[](std::size_t i)
//{
// return std::get<i>(tuple);
//}
};
int main()
{
constexpr c x;
static_assert( x.get<2>() == 'c' );
static_assert( x.get<1>() - 2.f < .1f );
static_assert( x.get<0>() == 1 );
//static_assert( x[2] == 'c' );
//static_assert( x[1] - 2.f < .1f );
//static_assert( x[0] == 1 );
}
Your operator[] must always return the same type for a given parameter type. The way to work around this is to make each parameter a different type.
For example:
template <std::size_t I>
using IndexConstantT = std::integral_constant<std::size_t, I>;
template <std::size_t I>
constexpr IndexConstantT<I> IndexConstant;
class c
{
std::tuple< int, float, char > tuple { 1, 2.f, 'c' };
public:
template <std::size_t i>
constexpr auto& operator[](IndexConstantT<i>) const
{
return std::get<i>(tuple);
}
};
int main()
{
constexpr const c x;
static_assert( x[IndexConstant<2>] == 'c' );
static_assert( x[IndexConstant<1>] - 2.f < .1f );
static_assert( x[IndexConstant<0>] == 1 );
}
Live Demo
As suggested by @NicolBolas in the comments, to make the syntax a little nicer, you could use a User Defined Literal so that you can use just 2_ic instead of IndexConstant<2>:
constexpr std::size_t c_to_i(char c)
{
return c - '0';
}
constexpr std::size_t constexpr_pow(std::size_t base, std::size_t exp)
{
std::size_t ret = 1;
for (std::size_t i = 0; i < exp; ++i) {
ret *= base;
}
return ret;
}
template <char... Cs, std::size_t... Is>
constexpr std::size_t to_size_t_impl(std::index_sequence<Is...>)
{
return ((c_to_i(Cs) * constexpr_pow(10, sizeof...(Is) - 1 - Is)) + ...);
}
template <char... Cs>
constexpr std::size_t to_size_t()
{
return to_size_t_impl<Cs...>(std::make_index_sequence<sizeof...(Cs)>{});
}
template <char... Cs>
constexpr auto operator""_ic()
{
return IndexConstant<to_size_t<Cs...>()>;
}
Live Demo
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With