Initial Course
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
add_course_exercise(NAME concepts MODULE 12_cpp20 STANDARD 20
|
||||
SOURCES src/concepts.cpp test/concepts_test.cpp)
|
||||
add_course_exercise(NAME ranges MODULE 12_cpp20 STANDARD 20
|
||||
SOURCES src/ranges.cpp test/ranges_test.cpp)
|
||||
add_course_exercise(NAME spaceship_operator MODULE 12_cpp20 STANDARD 20
|
||||
SOURCES src/spaceship_operator.cpp test/spaceship_operator_test.cpp)
|
||||
add_course_exercise(NAME span MODULE 12_cpp20 STANDARD 20
|
||||
SOURCES src/span.cpp test/span_test.cpp)
|
||||
@@ -0,0 +1,17 @@
|
||||
# Module 12: C++20 Major Features
|
||||
|
||||
## Learning Goals
|
||||
|
||||
- Constrain templates with concepts
|
||||
- Process sequences with the Ranges library
|
||||
- Compare values with the spaceship operator `<=>`
|
||||
- Pass non-owning views with `std::span`
|
||||
|
||||
## Exercises
|
||||
|
||||
| Exercise | Feature |
|
||||
|----------|---------|
|
||||
| `concepts` | Concepts and constrained templates |
|
||||
| `ranges` | Views and range algorithms |
|
||||
| `spaceship_operator` | `<=>` and comparison categories |
|
||||
| `span` | std::span non-owning spans |
|
||||
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <concepts>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace cpp20 {
|
||||
|
||||
template <std::integral T>
|
||||
[[nodiscard]] auto double_value(T value) -> T {
|
||||
(void)value;
|
||||
return T{};
|
||||
}
|
||||
|
||||
template <std::floating_point T>
|
||||
[[nodiscard]] auto clamp01(T value) -> T {
|
||||
(void)value;
|
||||
return T{};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
concept StringLike = requires(T value) {
|
||||
{ value.size() } -> std::convertible_to<std::size_t>;
|
||||
{ value.data() } -> std::convertible_to<const char*>;
|
||||
};
|
||||
|
||||
template <StringLike T>
|
||||
[[nodiscard]] auto uppercase_copy(const T& text) -> std::string {
|
||||
(void)text;
|
||||
return {};
|
||||
}
|
||||
|
||||
[[nodiscard]] auto sum_integral(const std::vector<int>& data) -> int;
|
||||
|
||||
} // namespace cpp20
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <ranges>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace cpp20 {
|
||||
|
||||
[[nodiscard]] auto even_numbers(const std::vector<int>& input) -> std::vector<int>;
|
||||
[[nodiscard]] auto take_first_three(const std::vector<int>& input) -> std::vector<int>;
|
||||
[[nodiscard]] auto join_strings(const std::vector<std::string>& parts) -> std::string;
|
||||
|
||||
} // namespace cpp20
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <compare>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace cpp20 {
|
||||
|
||||
struct Version {
|
||||
int major;
|
||||
int minor;
|
||||
int patch;
|
||||
|
||||
[[nodiscard]] auto operator<=>(const Version& other) const = default;
|
||||
};
|
||||
|
||||
[[nodiscard]] auto sort_versions(std::vector<Version> versions) -> std::vector<Version>;
|
||||
[[nodiscard]] auto is_sorted_versions(const std::vector<Version>& versions) -> bool;
|
||||
|
||||
} // namespace cpp20
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <span>
|
||||
#include <vector>
|
||||
|
||||
namespace cpp20 {
|
||||
|
||||
[[nodiscard]] auto span_sum(std::span<const int> data) -> int;
|
||||
[[nodiscard]] auto first_and_last(std::span<const int> data) -> std::pair<int, int>;
|
||||
[[nodiscard]] auto make_subspan(std::span<const int> data, std::size_t offset, std::size_t count)
|
||||
-> std::vector<int>;
|
||||
|
||||
} // namespace cpp20
|
||||
@@ -0,0 +1,10 @@
|
||||
#include "concepts.hpp"
|
||||
|
||||
namespace cpp20 {
|
||||
|
||||
auto sum_integral(const std::vector<int>& data) -> int {
|
||||
(void)data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace cpp20
|
||||
@@ -0,0 +1,20 @@
|
||||
#include "ranges.hpp"
|
||||
|
||||
namespace cpp20 {
|
||||
|
||||
auto even_numbers(const std::vector<int>& input) -> std::vector<int> {
|
||||
(void)input;
|
||||
return {};
|
||||
}
|
||||
|
||||
auto take_first_three(const std::vector<int>& input) -> std::vector<int> {
|
||||
(void)input;
|
||||
return {};
|
||||
}
|
||||
|
||||
auto join_strings(const std::vector<std::string>& parts) -> std::string {
|
||||
(void)parts;
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace cpp20
|
||||
@@ -0,0 +1,15 @@
|
||||
#include "spaceship_operator.hpp"
|
||||
|
||||
namespace cpp20 {
|
||||
|
||||
auto sort_versions(std::vector<Version> versions) -> std::vector<Version> {
|
||||
(void)versions;
|
||||
return {};
|
||||
}
|
||||
|
||||
auto is_sorted_versions(const std::vector<Version>& versions) -> bool {
|
||||
(void)versions;
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace cpp20
|
||||
@@ -0,0 +1,21 @@
|
||||
#include "span.hpp"
|
||||
|
||||
namespace cpp20 {
|
||||
|
||||
auto span_sum(std::span<const int> data) -> int {
|
||||
(void)data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto first_and_last(std::span<const int> data) -> std::pair<int, int> {
|
||||
(void)data;
|
||||
return {0, 0};
|
||||
}
|
||||
|
||||
auto make_subspan(std::span<const int> data, std::size_t offset, std::size_t count)
|
||||
-> std::vector<int> {
|
||||
(void)data; (void)offset; (void)count;
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace cpp20
|
||||
@@ -0,0 +1,19 @@
|
||||
#include "concepts.hpp"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(Concepts, DoubleValue) {
|
||||
EXPECT_EQ(cpp20::double_value(21), 42);
|
||||
}
|
||||
|
||||
TEST(Concepts, Clamp01) {
|
||||
EXPECT_DOUBLE_EQ(cpp20::clamp01(1.5), 1.0);
|
||||
EXPECT_DOUBLE_EQ(cpp20::clamp01(-0.5), 0.0);
|
||||
}
|
||||
|
||||
TEST(Concepts, UppercaseCopy) {
|
||||
EXPECT_EQ(cpp20::uppercase_copy(std::string{"hello"}), "HELLO");
|
||||
}
|
||||
|
||||
TEST(Concepts, SumIntegral) {
|
||||
EXPECT_EQ(cpp20::sum_integral({1, 2, 3}), 6);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#include "ranges.hpp"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(Ranges, EvenNumbers) {
|
||||
EXPECT_EQ(cpp20::even_numbers({1, 2, 3, 4, 5}), (std::vector<int>{2, 4}));
|
||||
}
|
||||
|
||||
TEST(Ranges, TakeFirstThree) {
|
||||
EXPECT_EQ(cpp20::take_first_three({9, 8, 7, 6, 5}), (std::vector<int>{9, 8, 7}));
|
||||
}
|
||||
|
||||
TEST(Ranges, JoinStrings) {
|
||||
EXPECT_EQ(cpp20::join_strings({"C", "++", "20"}), "C++20");
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#include "spaceship_operator.hpp"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(SpaceshipOperator, SortVersions) {
|
||||
const auto sorted = cpp20::sort_versions({{1, 10, 0}, {1, 2, 0}, {2, 0, 0}});
|
||||
ASSERT_EQ(sorted.size(), 3U);
|
||||
EXPECT_EQ(sorted[0].major, 1);
|
||||
EXPECT_EQ(sorted[0].minor, 2);
|
||||
EXPECT_EQ(sorted[2].major, 2);
|
||||
}
|
||||
|
||||
TEST(SpaceshipOperator, IsSorted) {
|
||||
EXPECT_TRUE(cpp20::is_sorted_versions({{1, 0, 0}, {1, 1, 0}, {2, 0, 0}}));
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#include "span.hpp"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(Span, SpanSum) {
|
||||
const int data[] = {1, 2, 3, 4};
|
||||
EXPECT_EQ(cpp20::span_sum(data), 10);
|
||||
}
|
||||
|
||||
TEST(Span, FirstAndLast) {
|
||||
const std::vector<int> data = {10, 20, 30};
|
||||
const auto [first, last] = cpp20::first_and_last(std::span<const int>{data});
|
||||
EXPECT_EQ(first, 10);
|
||||
EXPECT_EQ(last, 30);
|
||||
}
|
||||
|
||||
TEST(Span, MakeSubspan) {
|
||||
const std::vector<int> data = {1, 2, 3, 4, 5};
|
||||
EXPECT_EQ(cpp20::make_subspan(data, 1, 3), (std::vector<int>{2, 3, 4}));
|
||||
}
|
||||
Reference in New Issue
Block a user