operator[]
всегда должен возвращать один и тот же тип для данной перегрузки. Единственный способ выбора одной перегрузки над другим - через типы параметров, поэтому в этом случае, поскольку тип параметра всегда целочисленный, существует только одна перегрузка. Не допускаются неоднозначные перегрузки.
Мой метод полностью использует данные constexpr и использует тип возвращаемого значения вместо operator[]
. Я сделал это в структуре с использованием элементов данных stati c constexpr.
Шаблонные версии будут выделять функцию для каждого типа, представленного в качестве параметра.
Да, вы Можно использовать этот код для получения значения кортежа по указанному c индексу, но ваши варианты использования сужаются до контекста, который показан в примере ниже.
Вот как оно используется:
struct test
{
static constexpr array_operator_tuple<int, bool, unsigned> vals{ 1, true, 10u };
//
static constexpr auto r0 = vals[0];
//
// Equality operator
static_assert( r0 == 2, "The item required is not valid or not active." ); // Error as expected.
static_assert( r0 == 1, "The item required is not valid or not active." ); // No error as expected.
static_assert( r0 == true, "The item required is not valid or not active." ); // Error as expected.
static_assert( r0 == false, "The item required is not valid or not active." ); // Error as expected.
static_assert( r0 == 2u, "The item required is not valid or not active." ); // Error as expected.
static_assert( r0 == 10u, "The item required is not valid or not active." ); // Error as expected.
//
// Invalidity operator.
static_assert( r0 > 10u, "The item required is not valid or not active." ); // Error as expected.
static_assert( r0 <= 1u, "The item required is not valid or not active." ); // No error as expected.
static_assert( r0 < 9u, "The item required is not valid or not active." ); // No error as expected.
};
Код можно воспроизвести с помощью здесь .
#include <tuple>
#include <iostream>
template <typename T>
struct magic_item
{
T const * value = nullptr;
//
constexpr magic_item(T const * ptr) noexcept : value{ptr} {}
//
constexpr bool is_active() const noexcept
{
return value != nullptr;
}
constexpr bool is_value( T const & v ) const noexcept
{
return *value == v;
}
};
template <typename ... Args>
struct magic_tuple : std::tuple<magic_item<Args>...>
{
static constexpr size_t count = sizeof...(Args);
//
constexpr magic_tuple(Args const * ... args) noexcept :
std::tuple<magic_item<Args>...>{ {args}... }
{}
private:
template <size_t ... I>
constexpr bool active_index_impl(std::index_sequence<I...>) const noexcept
{
size_t output = ~static_cast<size_t>(0);
(((std::get<I>(*this) != nullptr) and (output = I, true)) or ...);
return output;
}
//
template <size_t ... I>
constexpr bool is_active_impl(size_t index, std::index_sequence<I...>) const noexcept
{
return (((index == I) and std::get<I>(*this).is_active()) or ...);
}
public:
constexpr bool is_active(size_t index) const noexcept
{
return is_active_impl(index, std::make_index_sequence<count>());
}
constexpr size_t active_index() const noexcept
{
return active_index_impl(std::make_index_sequence<count>());
}
//
template <typename T>
constexpr bool operator == (T const & value) const noexcept
{
using type = std::remove_cv_t<std::decay_t<T>>;
return std::get<magic_item<type>>(*this).is_active() and (*std::get<magic_item<type>>(*this).value == value);
}
template <typename T>
constexpr bool operator <= (T const & value) const noexcept
{
using type = std::remove_cv_t<std::decay_t<T>>;
return std::get<magic_item<type>>(*this).is_active() and (*std::get<magic_item<type>>(*this).value <= value);
}
template <typename T>
constexpr bool operator >= (T const & value) const noexcept
{
using type = std::remove_cv_t<std::decay_t<T>>;
return std::get<magic_item<type>>(*this).is_active() and (*std::get<magic_item<type>>(*this).value >= value);
}
template <typename T>
constexpr bool operator < (T const & value) const noexcept
{
using type = std::remove_cv_t<std::decay_t<T>>;
return std::get<magic_item<type>>(*this).is_active() and (*std::get<magic_item<type>>(*this).value < value);
}
template <typename T>
constexpr bool operator > (T const & value) const noexcept
{
using type = std::remove_cv_t<std::decay_t<T>>;
return std::get<magic_item<type>>(*this).is_active() and (*std::get<magic_item<type>>(*this).value > value);
}
};
//
template <typename ... Args, size_t ... I>
constexpr auto get_impl(size_t index, std::tuple<Args...> const & tup, std::index_sequence<I...>) -> magic_tuple< Args ... >
{
return magic_tuple< Args ... >{ ((index == I) ? &std::get<I>(tup) : nullptr ) ... };
}
template <typename ... Args>
constexpr auto get(size_t index, std::tuple<Args...> const & tup)
{
return get_impl(index, tup, std::make_index_sequence<sizeof...(Args)>{} );
}
//
template <typename ... Args>
struct array_operator_tuple : std::tuple<Args...>
{
using base_t= std::tuple<Args...>;
using base_t::base_t;
//
constexpr auto operator[](size_t index) const noexcept
{
return get(index, *this);
}
};
//
struct test
{
static constexpr array_operator_tuple<int, bool, unsigned> vals{ 1, true, 10u };
//
static constexpr auto r0 = vals[0];
//
static_assert( r0 == 2, "The item required is not valid or not active." ); // Error as expected.
static_assert( r0 == 1, "The item required is not valid or not active." ); // No error as expected.
static_assert( r0 == true, "The item required is not valid or not active." ); // Error as expected.
static_assert( r0 == false, "The item required is not valid or not active." ); // Error as expected.
static_assert( r0 == 2u, "The item required is not valid or not active." ); // Error as expected.
static_assert( r0 == 10u, "The item required is not valid or not active." ); // Error as expected.
//
static constexpr auto r1 = vals[1];
//
static_assert( r1 == 2, "The item required is not valid or not active." ); // Error as expected.
static_assert( r1 == 1, "The item required is not valid or not active." ); // Error as expected.
static_assert( r1 == true, "The item required is not valid or not active." ); // No error as expected.
static_assert( r1 == false, "The item required is not valid or not active." ); // Error as expected.
static_assert( r1 == 2u, "The item required is not valid or not active." ); // Error as expected.
static_assert( r1 == 10u, "The item required is not valid or not active." ); // Error as expected.
//
static constexpr auto r2 = vals[2];
//
static_assert( r2 == 2, "The item required is not valid or not active." ); // Error as expected.
static_assert( r2 == 1, "The item required is not valid or not active." ); // Error as expected.
static_assert( r2 == true, "The item required is not valid or not active." ); // Error as expected.
static_assert( r2 == false, "The item required is not valid or not active." ); // Error as expected.
static_assert( r2 == 2u, "The item required is not valid or not active." ); // Error as expected.
static_assert( r2 == 10u, "The item required is not valid or not active." ); // No error as expected.
//
static_assert( r2 > 10u, "The item required is not valid or not active." ); // Error as expected.
static_assert( r2 >= 10u, "The item required is not valid or not active." ); // No error as expected.
static_assert( r2 > 9u, "The item required is not valid or not active." ); // No error as expected.
};
//
int main()
{
test a{};
return 0;
}
Обычно не рекомендуется выводить из стандартной библиотеки, это просто демонстрация алгоритма.