Skip to content

Add std::tuple examples #678

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 15 additions & 20 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@
option(BOOST_UT_DISABLE_MODULE "Disable ut module" ON)

if(NOT BOOST_UT_DISABLE_MODULE)
cmake_minimum_required(VERSION 4.0.0)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "a9e1cf81-9932-4810-974b-6eccaf14e457")
set(CMAKE_CXX_MODULE_STD 1)
cmake_minimum_required(VERSION 4.0.0)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "a9e1cf81-9932-4810-974b-6eccaf14e457")
set(CMAKE_CXX_MODULE_STD 1)
set(CMAKE_CXX_SCAN_FOR_MODULES 1)
else()
cmake_minimum_required(VERSION 3.21...3.25)
cmake_minimum_required(VERSION 3.21...4.0)
endif()
project(
ut
Expand Down Expand Up @@ -40,12 +41,12 @@ option(BOOST_UT_USE_WARNINGS_AS_ERORS "Build the tests" ${PROJECT_IS_TOP_LEVEL})

add_library(ut INTERFACE)
if(NOT BOOST_UT_DISABLE_MODULE)
add_library(ut_module)
add_library(ut_module)
endif()
target_include_directories(ut INTERFACE $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>)
target_compile_features(ut INTERFACE cxx_std_20)
if(NOT BOOST_UT_DISABLE_MODULE)
target_compile_features(ut_module INTERFACE cxx_std_23)
target_compile_features(ut_module INTERFACE cxx_std_23)
endif()

if(BOOST_UT_USE_WARNINGS_AS_ERORS)
Expand Down Expand Up @@ -77,29 +78,27 @@ if(BOOST_UT_DISABLE_MODULE)
endif()

if(NOT BOOST_UT_DISABLE_MODULE)
target_sources(ut_module PUBLIC FILE_SET CXX_MODULES FILES include/boost/ut.cppm)
target_sources(ut_module PUBLIC FILE_SET CXX_MODULES FILES include/boost/ut.cppm)
endif()

if(NOT TARGET Boost::ut)
add_library(Boost::ut ALIAS ut)
endif()

if(NOT BOOST_UT_DISABLE_MODULE)
add_library(Boost::ut_module ALIAS ut_module)
add_library(Boost::ut_module ALIAS ut_module)
endif()

include(GNUInstallDirs)
include(CMakePackageConfigHelpers)

install(
FILES include/boost/ut.hpp include/boost/ut.cppm
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/boost
)
install(FILES include/boost/ut.hpp include/boost/ut.cppm DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/boost)

install(
TARGETS ut
EXPORT ut_Targets
INCLUDES DESTINATION include
INCLUDES
DESTINATION include
)
install(
EXPORT ut_Targets
Expand All @@ -111,13 +110,9 @@ install(
write_basic_package_version_file(
"utConfigVersion.cmake"
VERSION ${PROJECT_VERSION}
COMPATIBILITY SameMajorVersion
ARCH_INDEPENDENT
)
install(
FILES "${PROJECT_BINARY_DIR}/utConfigVersion.cmake"
DESTINATION lib/cmake/ut
COMPATIBILITY SameMajorVersion ARCH_INDEPENDENT
)
install(FILES "${PROJECT_BINARY_DIR}/utConfigVersion.cmake" DESTINATION lib/cmake/ut)

if(EMSCRIPTEN)
set(CMAKE_EXECUTABLE_SUFFIX ".js")
Expand Down
2 changes: 1 addition & 1 deletion cmake/WarningsAsErrors.cmake
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_SIMULATE_ID MATCHES "MSVC")
add_compile_options(/W4 /WX)
elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
add_compile_options(-Wall -Wextra -Wpedantic -Werror -Wshadow)
add_compile_options(-Wall -Wextra -Wpedantic -Werror -Wshadow -Wextra-semi)

if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION GREATER_EQUAL 10.0)
add_compile_options(-Wdeprecated-copy-dtor -Wnewline-eof)
Expand Down
1 change: 1 addition & 0 deletions example/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,5 @@ example(tag tag)
example(terse terse)
example(test _test)
example(tmp tmp)
example(tuple tuple)
example(using using)
178 changes: 178 additions & 0 deletions example/tuple.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
#include <atomic>
#include <boost/ut.hpp>
#include <iostream>
#include <optional>
#include <set>
#include <stdexcept>
#include <string>
#include <tuple>

void test_optional() {
using namespace boost::ut;

std::cout << std::boolalpha;

std::optional<int> opt;
std::cout << opt.has_value() << '\n';
expect(!opt);

opt = 43;
// Checks whether *this contains a value.
if (opt) {
std::cout << "value set to " << opt.value() << '\n';
} else {
std::cout << "value not set\n";
}
expect(opt.has_value());
expect(opt == 43);
expect(*opt);

opt.reset();
if (opt.has_value()) {
std::cout << "value still set to " << opt.value() << '\n';
} else {
std::cout << "value no longer set\n";
}
expect(!opt.has_value());
expect(!opt);
}

namespace {
std::optional<std::tuple<int, std::string>> findUserById(int id) {
if (id == 42) {
return std::make_tuple(42, "Alice");
} else {
return std::nullopt;
}
}

std::tuple<double, char, std::string> get_student(int id) {
switch (id) {
case 0:
return {3.8, 'A', "Lisa Simpson"};
case 1:
return {2.9, 'C', "Milhouse Van Houten"};
case 2:
return {1.7, 'D', "Ralph Wiggum"};
case 3:
return {0.6, 'F', "Bart Simpson"};
}

throw std::invalid_argument("id");
}

struct S {
int n;
std::string s;
double d;

friend bool operator<(const S& lhs, const S& rhs) noexcept {
// compares lhs.n to rhs.n,
// then lhs.s to rhs.s,
// then lhs.d to rhs.d
// in that order, first non-equal result is returned
// or false if all elements are equal
return std::tie(lhs.n, lhs.s, lhs.d) < std::tie(rhs.n, rhs.s, rhs.d);
}
};

std::tuple<int, int> divide(int a, int b) {
return std::make_tuple(a / b, a % b); // quotient and remainder
}

} // namespace

int main() {
using namespace boost::ut;

const auto student0 = get_student(0);
std::cout << "ID: 0, "
<< "GPA: " << std::get<0>(student0) << ", "
<< "grade: " << std::get<1>(student0) << ", "
<< "name: " << std::get<2>(student0) << '\n';
expect(std::tuple_size<decltype(student0)>::value == 3);
expect(std::get<2>(student0) == "Lisa Simpson");

const auto student1 = get_student(1);
std::cout << "ID: 1, "
<< "GPA: " << std::get<double>(student1) << ", "
<< "grade: " << std::get<char>(student1) << ", "
<< "name: " << std::get<std::string>(student1) << '\n';
expect(std::get<2>(student1) == "Milhouse Van Houten");

double gpa2{};
char grade2{};
std::string name2;
std::tie(gpa2, grade2, name2) = get_student(2);
std::cout << "ID: 2, "
<< "GPA: " << gpa2 << ", "
<< "grade: " << grade2 << ", "
<< "name: " << name2 << '\n';
expect(get_student(2) ==
std::tuple<double, char, std::string>{1.7, 'D', "Ralph Wiggum"});

// C++17 structured binding:
const auto [gpa3, grade3, name3] = get_student(3);
std::cout << "ID: 3, "
<< "GPA: " << gpa3 << ", "
<< "grade: " << grade3 << ", "
<< "name: " << name3 << '\n';
expect(get_student(3) ==
std::tuple<double, char, std::string>{0.6, 'F', "Bart Simpson"});

// Lexicographical comparison demo:
std::set<S> set_of_s;

S value{42, "Test", 3.14};
std::set<S>::iterator iter;
bool is_inserted{};

// Unpack a pair:
std::tie(iter, is_inserted) = set_of_s.insert(value);
expect(is_inserted);

// std::tie and structured bindings:
auto position = [](int w) { return std::tuple(1 * w, 2 * w); };

auto [x, y] = position(1);
expect(x == 1 && y == 2);
std::tie(x, y) = position(2); // reuse x, y with tie
expect(x == 2 && y == 4);

// Prevent warning C4244: 'initializing': conversion from '_Ty' to '_Ty', possible loss of data
// Implicit conversions are permitted:
// std::tuple<char, short> coordinates(6, 9);
// std::tie(x, y) = coordinates;
// expect(x == 6 && y == 9);

// Skip an element:
std::string z;
std::tie(x, std::ignore, z) = std::tuple(1, 2.0, "Test");
expect(x == 1 && z == "Test");

// Multiple Return Values
auto [quotient, remainder] = divide(10, 3);
expect(quotient == 3);
expect(remainder == 1);

expect(std::tuple(2, 1) == divide(5, 2));

std::atomic<bool> test_value{false};
expect(!test_value);

// test std::optional<std::tuple<>>
{
auto result = findUserById(42);
//FIXME: expect(result);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not compile?

if (result) {
// To unpack, use *result or result.value().
auto [userId, username] = *result; // unpack the tuple
std::cout << "Found user: " << userId << ", " << username << "\n";
} else {
std::cout << "User not found.\n";
}
expect(result != std::nullopt);
}

test_optional();
}
2 changes: 1 addition & 1 deletion include/boost/ut.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2626,7 +2626,7 @@ constexpr auto operator""_b(const char* name, decltype(sizeof("")) size) {
return "rd";
}
return "th";
};
}

template <class TArg>
inline std::string format_test_parameter([[maybe_unused]] const TArg& arg,
Expand Down
Loading