Skip to content
Snippets Groups Projects
Commit f0551846 authored by Sandipan Mohanty's avatar Sandipan Mohanty
Browse files

Chapter 3 examples

parent 02774a29
Branches
No related tags found
No related merge requests found
Showing
with 436 additions and 0 deletions
cmake_minimum_required(VERSION 3.28)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
project(cxx_course_examples CXX)
FILE (GLOB sources ./ *.cc)
foreach(source ${sources})
get_filename_component(withoutext "${source}" NAME_WE)
add_executable("${withoutext}" "${source}")
endforeach()
#include <iostream>
#include <string>
#include <concepts>
template <class T>
concept Addable = requires(T a, T b) {
{ a + b } -> std::convertible_to<T>;
};
auto aggregate(Addable auto... args)
{
return (args + ...);
}
auto main() -> int
{
using namespace std::string_literals;
std::cout << "aggregate(1, 2, 3, 4, 5) = "
<< aggregate(1, 2, 3, 4, 5) << "\n";
std::cout << R"aw(aggregate("|-"s, "-|"s) = )aw"
<< aggregate("|-"s, "-|"s) << "\n";
}
#include <iostream>
#include <string>
#include <vector>
auto add_up(auto... args)
{
return (args + ...);
}
template <typename T>
void push_back(std::vector<T> &v, auto ... args) {
(v.push_back(args), ...);
}
auto main() -> int
{
using namespace std;
string firstname{ "Steve" }, lastname{ "Rogers" };
cout << add_up(1, 2, 3, 4, 5) << "\n";
cout << add_up(firstname, " ", lastname) << "\n";
std::vector<double> q{0.0};
push_back(q, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8);
for (auto d : q) cout << d << "\n";
}
#include <vector>
#include <iostream>
#include <algorithm>
#include <ranges>
#include <string>
#include "print_tuple.hh"
auto max_of_multiple(auto ... containers)
{
return std::make_tuple(std::ranges::max(containers) ...);
}
auto main() -> int
{
std::vector v1{8.2, 84., 9.1, 33.1, 9.33, 8.2, 8.3};
std::vector v2{9,1,2,8,3,1,4,2,0,8,1};
std::vector<std::string> v3{"Compact", "code", "with", "fold", "expressions"};
std::cout << max_of_multiple(v1, v2, v3) << "\n";
}
#include <vector>
#include <iostream>
#include <ranges>
#include <algorithm>
#include "range_output.hh"
auto conv(const std::vector<double>& inp, auto ... shift)
{
namespace sr = std::ranges;
namespace sv = std::views;
std::vector<double> out(inp.size(), 0.);
auto res_exp = sv::iota(0, static_cast<int>(inp.size()))
| sv::transform([inp, shift...](auto index){
auto S = inp.size();
return (inp[(index + shift) > 0 ? (index + shift) % S : S + (index + shift) % S] + ...)
/ (sizeof ... (shift));
});
sr::copy(res_exp, out.begin());
return out;
}
auto main() -> int
{
std::vector v(21UL, 0.);
v[10] = 1.0;
for (auto i = 0UL; i < 10; ++i) {
v = conv(v, 0, 1, 2);
std::cout << "After round " << i << ", v = " << output::comma_separated << v << "\n";
}
}
#include <iostream>
#include <string>
#include <vector>
template <typename... Args>
auto add_up(Args... args)
{
return (args + ...);
}
template <typename T, typename... Args>
void push_back(std::vector<T> &v, Args ... args) {
(v.push_back(args), ...);
}
auto main() -> int
{
using namespace std;
string firstname{ "Stephen" }, lastname{ "Hawking" };
cout << add_up(1, 2, 3, 4, 5) << "\n";
cout << add_up(firstname, " ", lastname) << "\n";
std::vector<double> q{0.0};
push_back(q, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8);
for (auto d : q) cout << d << "\n";
}
// examples/foldex_3.cc
#include <algorithm>
template <class First, class... Args>
auto min(First first, Args... args)
{
First retval = first;
((retval = std::min(retval, args)), ...);
return retval;
}
int main()
{
return min(8, 3, 4, 7, 2, 7) + min(2, 3, 9, 1);
}
#include <iostream>
#include <type_traits>
template <class T>
concept Integral = std::is_integral_v<T>;
constexpr auto gcd(Integral auto a, Integral auto b)
{
if (b == 0)
return a;
return gcd(b, a % b);
}
auto main() -> int
{
// Wont compile, until both the following arguments
// are changed into integral types.
std::cout << gcd(149935, 47295.) << "\n";
}
#include <iostream>
#include <string>
auto f(auto i1, auto i2)
{
return i1 + i2;
}
// Same as above, but enforce that the parameters have the same type
template <class T>
auto g(T i1, T i2)
{
return i1 + i2;
}
int main()
{
using namespace std::string_literals;
std::cout << f(1, 2) << "\n";
std::cout << f(1.2, 2.2) << "\n";
std::cout << f("1"s, "2"s) << "\n";
//std::cout << f("1"s, 2) << "\n"; // Does not work
std::cout << g("1"s, 2) << "\n"; // Does not work, but better errors
}
#include <iostream>
#include <string>
// Same as above, but enforce that the parameters have the same type
template <class T>
auto f(T i1, T i2)
{
return i1 + i2;
}
auto main() -> int
{
using namespace std::string_literals;
std::cout << f("1", "2") << "\n";
// Does not work, because it's an invalid use of the function f. We wrote that for things which are addable.
// How did we try to indicate this intention of "addability" of the arguments ?
// Answer : We didn't!
// If the function had been 50 lines instead of 1, the real error would be very hard to
// decipher. There is an assumption regarding incoming arguments in our function template,
// and we did not specify that assumption anywhere. How does one indicate such constraints ?
// Answer(C++20) : concepts
// Answer(C++ < C++20) : std::enable_if, type_traits and some acrobatic programming.
}
#include <iostream>
#include <string>
#include <concepts>
template <class T>
concept Addable = requires(T a, T b) {
{ a + b } -> std::convertible_to<T>;
};
auto f(Addable auto i1, Addable auto i2)
{
return i1 + i2;
}
int main()
{
using namespace std::string_literals;
std::cout << f(1, 2) << "\n";
std::cout << f("1"s, "2"s) << "\n";
std::cout << f("1", "2") << "\n";
}
#include <iostream>
#include <string>
template <class T>
concept Addable = requires(T a, T b) {
{ a + b } ;
};
template <class T> concept NotAddable = not Addable<T>;
auto f(Addable auto i1, Addable auto i2)
{
std::cout << "(using version of function f with Addable parameters) ... ";
return i1 + i2;
}
auto f(NotAddable auto i1, NotAddable auto i2)
{
std::cout << "(using version of function f with NotAddable parameters) ... ";
return i1;
}
int main()
{
using namespace std::string_literals;
std::cout << "f(1, 2) --> " << f(1, 2) << "\n";
std::cout << R"(f("1"s, "2"s) --> )" << f("1"s, "2"s) << "\n";
std::cout << R"(f("1", "2") --> )" << f("1", "2") << "\n";
}
template <unsigned N> constexpr unsigned fact = N * fact<N-1>;
template <> constexpr unsigned fact<0> = 1U;
static_assert(fact<7> == 5040);
template <class A, class B>
constexpr auto are_same = false;
template <class A>
constexpr auto are_same<A, A> = true;
//static_assert(are_same<int, unsigned int>);
using Integer = int;
static_assert(are_same<int, Integer>);
auto main() -> int {}
// examples/overload_w_concepts.cc
#include <print>
#include <concepts>
#include <string>
#include <typeinfo>
template <class N> concept Number = std::is_floating_point_v<N> || std::is_integral_v<N>;
template <class N> concept NotNumber = not Number<N>;
void proc(Number auto&& x)
{
std::print("Called proc for numbers with {} of typeid {}\n", x, typeid(x).name());
}
void proc(NotNumber auto&& x)
{
std::print("Called proc for non-numbers with {} of typeid {}\n", x, typeid(x).name());
}
auto main() -> int
{
using namespace std::string_literals;
proc(-1);
proc(88UL);
proc("0118 999 88191 9119725 3");
proc(3.141);
proc("eighty"s);
}
#include <iostream>
#include <string>
#include <tuple>
template <int idx, int MAX, typename... Args>
struct PRINT_TUPLE {
static void print(std::ostream& strm, const std::tuple<Args...>& t)
{
strm << std::get<idx>(t) << (idx + 1 == MAX ? "" : ", ");
PRINT_TUPLE<idx + 1, MAX, Args...>::print(strm, t);
}
};
template <int MAX, typename... Args>
struct PRINT_TUPLE<MAX, MAX, Args...> {
static void print(std::ostream& strm, const std::tuple<Args...>& t)
{
}
};
template <typename... Args>
std::ostream& operator<<(std::ostream& strm, const std::tuple<Args...>& t)
{
strm << "[";
PRINT_TUPLE<0, sizeof...(Args), Args...>::print(strm, t);
return strm << "]";
}
auto main() -> int
{
std::tuple<int, std::string, double, int, double > t{23,"abc",3.141, 3, 2.718};
std::cout << t << "\n";
}
#include <iostream>
#include <string>
#include <tuple>
template <int idx, int MAX, typename... Args>
struct PRINT_TUPLE {
static void print(std::ostream& strm, const std::tuple<Args...>& t)
{
if
constexpr(idx < MAX)
{
strm << std::get<idx>(t);
if
constexpr((idx + 1) < MAX) strm << ", ";
PRINT_TUPLE<idx + 1, MAX, Args...>::print(strm, t);
}
}
};
template <typename... Args>
auto operator<<(std::ostream& strm, const std::tuple<Args...>& t) -> std::ostream&
{
strm << "[";
PRINT_TUPLE<0, sizeof...(Args), Args...>::print(strm, t);
return strm << "]";
}
auto main() -> int
{
std::tuple<int, std::string, double, int, double> t{ 23, "abc", 3.141, 3, 2.718 };
std::cout << t << "\n";
}
#include <print>
#include <tuple>
#include <string_view>
auto main() -> int
{
using namespace std::literals;
std::tuple t{0.1, 11, "eleven hundred"sv};
std::print("{}\n", t);
}
#include <tuple>
#include <iostream>
#include <iomanip>
template <class ... Args>
auto operator<<(std::ostream & strm, const std::tuple<Args...> & t) -> std::ostream &
{
using namespace std;
auto print_one = [&strm](const auto & onearg) -> ostream & {
using bare_type = remove_cv_t<remove_reference_t<decltype(onearg)>>;
if constexpr (is_same_v<bare_type, string>)
strm << quoted(onearg);
else
strm << onearg;
return strm;
};
auto print_components = [&](const auto & ... args){
((print_one(args) << ", "), ...);
};
strm << "[";
apply(print_components, t);
return strm <<"]";
}
auto main() -> int
{
std::tuple t1{1, "one"};
std::tuple t2{2, "two", "II", 2.0};
std::cout << t1 << "\t" << t2 << "\n";
}
auto advance(unsigned long L) -> double
{
static_assert(sizeof(L) >= 8, "long must be at least 8 bytes. ");
//Bit manipulation assuming "long" is at least 8 bytes
return static_cast<double>(L);
}
auto main() -> int {}
auto advance(unsigned long i) -> double
{
static_assert(sizeof(i) >= 8, "long must be bigger than 8 bytes");
return 0.;
}
auto main() -> int {}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment