Last active
February 12, 2023 09:14
-
-
Save furfurylic/0a91c15f4f9f9d6ec70cdc398d34f021 to your computer and use it in GitHub Desktop.
lab - tuple_get_n
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
Create a new tuple out of an existing tuple in 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
build |
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
cmake_minimum_required(VERSION 3.13) | |
project(test_tuple_get_n CXX) | |
set(CMAKE_CXX_STANDARD 17) | |
set(CMAKE_CXX_STANDARD_REQUIRED ON) | |
set(CMAKE_CXX_EXTENSIONS OFF) | |
set_property(GLOBAL PROPERTY USE_FOLDERS ON) | |
enable_testing() | |
include(FetchContent) | |
FetchContent_Declare( | |
googletest | |
GIT_REPOSITORY https://github.com/google/googletest.git | |
GIT_TAG v1.13.0 | |
) | |
FetchContent_GetProperties(googletest) | |
if(NOT googletest_POPULATED) | |
FetchContent_Populate(googletest) | |
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) | |
add_subdirectory(${googletest_SOURCE_DIR} | |
${googletest_BINARY_DIR} | |
EXCLUDE_FROM_ALL) | |
endif() | |
set_target_properties(gtest gtest_main PROPERTIES FOLDER "Dependencies") | |
add_executable(test_tuple_get_n) | |
target_sources(test_tuple_get_n PRIVATE | |
tuple_get_n.hpp | |
tuple_tail.hpp | |
test_tuple_get_n.cpp | |
test_tuple_tail.cpp | |
) | |
target_compile_features(test_tuple_get_n PRIVATE cxx_std_17) | |
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") | |
target_compile_options(test_tuple_get_n PRIVATE | |
/MP /W4 /bigobj | |
$<$<CONFIG:MinSizeRel>:/wd4702> | |
$<$<CONFIG:Release>:/wd4702> | |
$<$<CONFIG:RelWithDebInfo>:/wd4702> | |
) | |
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") | |
target_compile_definitions(test_tuple_get_n PRIVATE | |
$<$<NOT:$<CONFIG:Debug>>:NDEBUG> | |
) | |
target_compile_options(test_tuple_get_n PRIVATE | |
-Wall -Wextra -pedantic-errors -Werror=pedantic | |
$<$<CONFIG:Debug>:-O0 -g3> | |
$<$<CONFIG:RelWithDebInfo>:-O2 -g3> | |
) | |
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") | |
target_compile_definitions(test_tuple_get_n PRIVATE | |
$<$<NOT:$<CONFIG:Debug>>:NDEBUG> | |
) | |
target_compile_options(test_tuple_get_n PRIVATE | |
-Wall -Wextra -pedantic-errors -Werror=pedantic | |
-Wno-gnu-zero-variadic-macro-arguments | |
$<$<CONFIG:Debug>:-O0 -g3> | |
$<$<CONFIG:RelWithDebInfo>:-O2 -g3> | |
) | |
endif() | |
target_link_libraries(test_tuple_get_n PRIVATE gtest gtest_main) | |
add_test( | |
NAME test_tuple_get_n | |
COMMAND $<TARGET_FILE:test_tuple_get_n> | |
) |
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
/* | |
* These codes are available under CC0 1.0 Universal. | |
* https://creativecommons.org/publicdomain/zero/1.0/deed | |
*/ | |
#include <string> | |
#include <tuple> | |
#include <type_traits> | |
#include <gtest/gtest.h> | |
#include "tuple_get_n.hpp" | |
using namespace std::literals::string_literals; | |
using namespace furfurylic::lab; | |
namespace { | |
// A type whose moved-from states are value-initialized ones | |
template <class T> | |
struct move_to_valinit { | |
T t; | |
template <class U, | |
std::enable_if_t<!std::is_base_of_v<move_to_valinit, std::decay_t<U>>>* | |
= nullptr> | |
explicit move_to_valinit(U&& u) : t(std::forward<U>(u)) | |
{} | |
move_to_valinit(move_to_valinit&& other) | |
noexcept(std::is_nothrow_move_assignable_v<T> | |
&& std::is_nothrow_default_constructible_v<T>) :// to squelch VS2019 | |
t(std::exchange(other.t, T())) | |
{} | |
move_to_valinit(const move_to_valinit&) = default; | |
}; | |
} | |
TEST(TestTupleGetN, Copy) { | |
using S = move_to_valinit<std::string>; | |
std::tuple<int, S, double, long> t(10, S("ABC"), 3.14, -20); | |
auto u = get_n<3, 1>(t); | |
static_assert(std::is_same_v<std::tuple<long, move_to_valinit<std::string>>, | |
decltype(u)>); | |
ASSERT_EQ(-20, std::get<0>(u)); | |
ASSERT_EQ("ABC"s, std::get<1>(u).t); | |
ASSERT_EQ("ABC"s, std::get<1>(t).t); // of course, not moved from | |
} | |
TEST(TestTupleGetN, Move) { | |
using S = move_to_valinit<std::string>; | |
std::tuple<int, S, double, long> t(10, S("ABC"), 3.14, -20); | |
auto u = get_n<3, 1>(std::move(t)); | |
static_assert(std::is_same_v<std::tuple<long, S>, decltype(u)>); | |
ASSERT_EQ(-20, std::get<0>(u)); | |
ASSERT_EQ("ABC"s, std::get<1>(u).t); | |
ASSERT_TRUE(std::get<1>(t).t.empty()); // moved-from state | |
} | |
TEST(TestTupleGetN, LvalueRef) { | |
int l = 1; | |
float m = 5.0; | |
char n = 'A'; | |
auto t = std::tie(l, m, n); | |
auto u = get_n<2, 0>(t); | |
static_assert(std::is_same_v<std::tuple<char&, int&>, decltype(u)>); | |
std::get<1>(u) *= -1; // modify n through an lvalue reference in u | |
ASSERT_EQ(-1, l); | |
auto v = get_n<1>(std::move(u)); | |
static_assert(std::is_same_v<std::tuple<int&>, decltype(v)>); | |
// holds an lvalue reference (not rvalue one) | |
ASSERT_EQ(&l, &std::get<0>(v)); | |
} | |
TEST(TestTupleGetN, RvalueRef) { | |
using S = move_to_valinit<std::string>; | |
int l = 1; | |
S m("XYZ"); | |
auto t = std::forward_as_tuple(std::move(l), std::move(m)); | |
static_assert(std::is_same_v<std::tuple<int&&, S&&>, decltype(t)>); | |
// auto u = get_n<0, 1>(t); | |
// This does not compile, which corresponds with the below code, which also | |
// does not | |
// auto u = t; | |
auto v = get_n<0, 1>(std::move(t)); | |
static_assert(std::is_same_v<decltype(t), decltype(v)>); | |
ASSERT_EQ("XYZ"s, m.t); // rvalue references copied but no move occurred | |
std::string s = std::get<1>(std::move(v)).t; // move occurs | |
ASSERT_EQ("XYZ"s, s); | |
ASSERT_TRUE(m.t.empty()); | |
} | |
static_assert(std::make_tuple(42, 800) | |
== get_n<2, 0>(std::make_tuple(800, 3.14, 42))); |
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
/* | |
* These codes are available under CC0 1.0 Universal. | |
* https://creativecommons.org/publicdomain/zero/1.0/deed | |
*/ | |
#include <string> | |
#include <tuple> | |
#include <type_traits> | |
#include <gtest/gtest.h> | |
#include "tuple_tail.hpp" | |
using namespace furfurylic::lab; | |
TEST(TestTail, All) { | |
int n = 42; | |
std::tuple<std::string, int&, double> v("ABC", n, 3.14); | |
auto t = tail(v); | |
static_assert(std::is_same_v<std::tuple<int&, double>, decltype(t)>); | |
std::get<int&>(t) = 100; | |
ASSERT_EQ(100, n); | |
const auto t1 = std::get<double>(t); | |
ASSERT_EQ(3.14, t1); | |
} | |
static_assert(std::make_tuple(2, 3) == tail(std::make_tuple(1, 2, 3))); | |
static_assert(std::is_same_v<std::tuple<>, | |
decltype(tail(std::make_tuple(42)))>); |
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
/* | |
* These codes are available under CC0 1.0 Universal. | |
* https://creativecommons.org/publicdomain/zero/1.0/deed | |
*/ | |
#ifndef FURFURYLIC_LAB_GUARD_3E8575E2_2433_45EE_9B72_CA8C38DFA233 | |
#define FURFURYLIC_LAB_GUARD_3E8575E2_2433_45EE_9B72_CA8C38DFA233 | |
#include <cstddef> | |
#include <tuple> | |
#include <type_traits> | |
#include <utility> | |
namespace furfurylic::lab { | |
template <std::size_t... Is, class Tuple> | |
constexpr std::tuple<std::tuple_element_t<Is, std::decay_t<Tuple>>...> | |
get_n(Tuple&& t) { | |
return { std::get<Is>(std::forward<Tuple>(t))... }; | |
} | |
} | |
#endif |
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
/* | |
* These codes are available under CC0 1.0 Universal. | |
* https://creativecommons.org/publicdomain/zero/1.0/deed | |
*/ | |
#ifndef FURFURYLIC_LAB_GUARD_62190A1A_B9A3_4AB8_BDC1_C013D5B90AC5 | |
#define FURFURYLIC_LAB_GUARD_62190A1A_B9A3_4AB8_BDC1_C013D5B90AC5 | |
#include <functional> | |
#include "tuple_get_n.hpp" | |
namespace furfurylic::lab { | |
namespace detail { | |
template <std::size_t... Is, class Tuple> | |
constexpr auto tail_impl(std::index_sequence<Is...>, Tuple&& t) { | |
return get_n<(Is + 1)...>(std::forward<Tuple>(t)); | |
} | |
template <class T0, class... Ts> | |
std::tuple<Ts...> tail_type(const std::tuple<T0, Ts...>&); | |
} | |
template <class Tuple> | |
constexpr decltype(detail::tail_type(std::declval<Tuple>())) tail(Tuple&& t) { | |
return detail::tail_impl( | |
std::make_index_sequence<std::tuple_size_v<std::decay_t<Tuple>> - 1>(), | |
std::forward<Tuple>(t)); | |
} | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment