Initial Course
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
add_course_exercise(NAME structured_bindings MODULE 11_cpp17 STANDARD 17
|
||||
SOURCES src/structured_bindings.cpp test/structured_bindings_test.cpp)
|
||||
add_course_exercise(NAME optional MODULE 11_cpp17 STANDARD 17
|
||||
SOURCES src/optional.cpp test/optional_test.cpp)
|
||||
add_course_exercise(NAME variant MODULE 11_cpp17 STANDARD 17
|
||||
SOURCES src/variant.cpp test/variant_test.cpp)
|
||||
add_course_exercise(NAME if_constexpr MODULE 11_cpp17 STANDARD 17
|
||||
SOURCES src/if_constexpr.cpp test/if_constexpr_test.cpp)
|
||||
@@ -0,0 +1,17 @@
|
||||
# Module 11: C++17 Features
|
||||
|
||||
## Learning Goals
|
||||
|
||||
- Destructure tuples and pairs with structured bindings
|
||||
- Model optional values with `std::optional`
|
||||
- Represent alternatives with `std::variant`
|
||||
- Use `if constexpr` and fold expressions
|
||||
|
||||
## Exercises
|
||||
|
||||
| Exercise | Feature |
|
||||
|----------|---------|
|
||||
| `structured_bindings` | Structured bindings |
|
||||
| `optional` | std::optional |
|
||||
| `variant` | std::variant + std::visit |
|
||||
| `if_constexpr` | Compile-time branching |
|
||||
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace cpp17 {
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr auto type_name() -> const char* {
|
||||
if constexpr (std::is_integral_v<T>) {
|
||||
return "integral";
|
||||
} else if constexpr (std::is_floating_point_v<T>) {
|
||||
return "floating";
|
||||
} else {
|
||||
return "other";
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
[[nodiscard]] auto element_count(const Container& container) -> std::size_t {
|
||||
if constexpr (std::is_member_function_pointer_v<decltype(&Container::size)>) {
|
||||
return container.size();
|
||||
} else {
|
||||
std::size_t count = 0;
|
||||
for ([[maybe_unused]] const auto& item : container) {
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] auto stringify_ints(const std::vector<int>& data) -> std::string;
|
||||
|
||||
} // namespace cpp17
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace cpp17 {
|
||||
|
||||
[[nodiscard]] auto safe_divide(int lhs, int rhs) -> std::optional<double>;
|
||||
[[nodiscard]] auto find_user(const std::vector<std::string>& users, const std::string& name)
|
||||
-> std::optional<std::size_t>;
|
||||
[[nodiscard]] auto first_positive(const std::vector<int>& data) -> std::optional<int>;
|
||||
|
||||
} // namespace cpp17
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
namespace cpp17 {
|
||||
|
||||
[[nodiscard]] auto minmax_pair(const std::vector<int>& data) -> std::pair<int, int>;
|
||||
[[nodiscard]] auto split_key_value(const std::string& text) -> std::pair<std::string, std::string>;
|
||||
[[nodiscard]] auto first_pair(const std::map<std::string, int>& scores)
|
||||
-> std::tuple<std::string, int, bool>;
|
||||
|
||||
} // namespace cpp17
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
namespace cpp17 {
|
||||
|
||||
using Value = std::variant<int, double, std::string>;
|
||||
|
||||
[[nodiscard]] auto variant_to_string(const Value& value) -> std::string;
|
||||
[[nodiscard]] auto sum_numeric_variants(const std::vector<Value>& values) -> double;
|
||||
[[nodiscard]] auto is_string(const Value& value) -> bool;
|
||||
|
||||
} // namespace cpp17
|
||||
@@ -0,0 +1,12 @@
|
||||
#include "if_constexpr.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace cpp17 {
|
||||
|
||||
auto stringify_ints(const std::vector<int>& data) -> std::string {
|
||||
(void)data;
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace cpp17
|
||||
@@ -0,0 +1,21 @@
|
||||
#include "optional.hpp"
|
||||
|
||||
namespace cpp17 {
|
||||
|
||||
auto safe_divide(int lhs, int rhs) -> std::optional<double> {
|
||||
(void)lhs; (void)rhs;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto find_user(const std::vector<std::string>& users, const std::string& name)
|
||||
-> std::optional<std::size_t> {
|
||||
(void)users; (void)name;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto first_positive(const std::vector<int>& data) -> std::optional<int> {
|
||||
(void)data;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace cpp17
|
||||
@@ -0,0 +1,20 @@
|
||||
#include "structured_bindings.hpp"
|
||||
|
||||
namespace cpp17 {
|
||||
|
||||
auto minmax_pair(const std::vector<int>& data) -> std::pair<int, int> {
|
||||
(void)data;
|
||||
return {0, 0};
|
||||
}
|
||||
|
||||
auto split_key_value(const std::string& text) -> std::pair<std::string, std::string> {
|
||||
(void)text;
|
||||
return {"", ""};
|
||||
}
|
||||
|
||||
auto first_pair(const std::map<std::string, int>& scores) -> std::tuple<std::string, int, bool> {
|
||||
(void)scores;
|
||||
return {"", 0, false};
|
||||
}
|
||||
|
||||
} // namespace cpp17
|
||||
@@ -0,0 +1,20 @@
|
||||
#include "variant.hpp"
|
||||
|
||||
namespace cpp17 {
|
||||
|
||||
auto variant_to_string(const Value& value) -> std::string {
|
||||
(void)value;
|
||||
return {};
|
||||
}
|
||||
|
||||
auto sum_numeric_variants(const std::vector<Value>& values) -> double {
|
||||
(void)values;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
auto is_string(const Value& value) -> bool {
|
||||
(void)value;
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace cpp17
|
||||
@@ -0,0 +1,15 @@
|
||||
#include "if_constexpr.hpp"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(IfConstexpr, TypeName) {
|
||||
EXPECT_STREQ(cpp17::type_name<int>(), "integral");
|
||||
EXPECT_STREQ(cpp17::type_name<double>(), "floating");
|
||||
}
|
||||
|
||||
TEST(IfConstexpr, ElementCount) {
|
||||
EXPECT_EQ(cpp17::element_count(std::vector<int>{1, 2, 3}), 3U);
|
||||
}
|
||||
|
||||
TEST(IfConstexpr, StringifyInts) {
|
||||
EXPECT_EQ(cpp17::stringify_ints({1, 2, 3}), "1,2,3");
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#include "optional.hpp"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(Optional, SafeDivide) {
|
||||
EXPECT_DOUBLE_EQ(*cpp17::safe_divide(10, 2), 5.0);
|
||||
EXPECT_FALSE(cpp17::safe_divide(1, 0).has_value());
|
||||
}
|
||||
|
||||
TEST(Optional, FindUser) {
|
||||
EXPECT_EQ(*cpp17::find_user({"Ada", "Grace"}, "Grace"), 1U);
|
||||
}
|
||||
|
||||
TEST(Optional, FirstPositive) {
|
||||
EXPECT_EQ(*cpp17::first_positive({-1, 0, 3, 4}), 3);
|
||||
EXPECT_FALSE(cpp17::first_positive({-1, -2}).has_value());
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#include "structured_bindings.hpp"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(StructuredBindings, MinMaxPair) {
|
||||
const auto [min, max] = cpp17::minmax_pair({3, 1, 9, 2});
|
||||
EXPECT_EQ(min, 1);
|
||||
EXPECT_EQ(max, 9);
|
||||
}
|
||||
|
||||
TEST(StructuredBindings, SplitKeyValue) {
|
||||
const auto [key, value] = cpp17::split_key_value("name=Ada");
|
||||
EXPECT_EQ(key, "name");
|
||||
EXPECT_EQ(value, "Ada");
|
||||
}
|
||||
|
||||
TEST(StructuredBindings, FirstPair) {
|
||||
const std::map<std::string, int> scores{{"Ada", 100}, {"Grace", 95}};
|
||||
const auto [name, score, found] = cpp17::first_pair(scores);
|
||||
EXPECT_TRUE(found);
|
||||
EXPECT_EQ(name, "Ada");
|
||||
EXPECT_EQ(score, 100);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "variant.hpp"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(Variant, VariantToString) {
|
||||
EXPECT_EQ(cpp17::variant_to_string(42), "int:42");
|
||||
EXPECT_EQ(cpp17::variant_to_string(std::string{"hi"}), "string:hi");
|
||||
}
|
||||
|
||||
TEST(Variant, SumNumericVariants) {
|
||||
const std::vector<cpp17::Value> values{1, 2.5, std::string{"x"}, 3.5};
|
||||
EXPECT_DOUBLE_EQ(cpp17::sum_numeric_variants(values), 7.0);
|
||||
}
|
||||
|
||||
TEST(Variant, IsString) {
|
||||
EXPECT_TRUE(cpp17::is_string(std::string{"ok"}));
|
||||
EXPECT_FALSE(cpp17::is_string(1));
|
||||
}
|
||||
Reference in New Issue
Block a user