C++ Ranges

starting from c++ std 20 you can ranges STL library is coming up

first example


    #include "ranges"

    auto const ints =std::vector<int>{0,1,2,3,4,5};
    auto even = [](int i) { return 0 == i % 2; };
    auto square = [](int i) { return i * i; };

    auto res=ints | std::views::filter(even) | std::views::transform(square);
    for(const int& v : res){
        qDebug()<<v;
    }

the ranges it executed once start iterate it this in c++ std but in ranges-v3 you have to use ranges::views::indirect

auto vec=v::iota(-100,100)|v::take(10)|v::filter([](int val)->bool{return true;})|v::transform([](int val)->int{qDebug()<<val;return abs(val);});
    for (int i : vec) {
        qDebug()<< i ;
    }

-100 100
-99 99
-98 98
-97 97
-96 96
-95 95
-94 94
-93 93
-92 92
-91 91

zip ranges

    std::vector<int> vals{1,2,3,4,5,6};
    std::vector<int> vals2{11,22,33};
    auto res2=ranges::views::zip(vals,vals2);
    for(auto [val1,val2] : res2)
        std::cout<<val1<<":"<<val2<<std::endl;
//1:11   2:22   3:33

convert the output to vector

auto res=vals|ranges::views::take(5)|ranges::to<std::vector<int>>();

cycle the ranges

    std::vector<int> values{343,35,45,324,5,4};
    ranges::sort(values);//4 5 35 45 324 343
    auto res=values|ranges::views::take(100)|ranges::views::all|ranges::views::transform([](int v){ return v+45; })|ranges::to<std::vector<int>>();
    auto res2=res|ranges::views::cycle|ranges::views::take(10); //49 50 80 90 369 388 49 50 80 90 

Generate and accumilate

auto vi = views::for_each(views::ints(1, 6), [](int i) { return yield_from(views::repeat_n(i, i)); }) |to<std::vector>();
    // prints: [1,2,2,3,3,3,4,4,4,4,5,5,5,5,5]
int sum = accumulate(views::ints(1, unreachable) | views::transform([](int i) {
                             return i * i;
                         }) | views::take(10),
                         0);
    // prints: 385

Actions

std::vector<int> vi{9, 4, 5, 2, 9, 1, 0, 2, 6, 7, 4, 5, 6, 5, 9, 2, 7,
                        1, 4, 5, 3, 8, 5, 0, 2, 9, 3, 7, 5, 7, 5, 5, 6, 1,
                        4, 3, 1, 8, 4, 0, 7, 8, 8, 2, 6, 5, 3, 4, 5};
    using namespace ranges;
    vi |= actions::sort | actions::unique;
    // prints: [0,1,2,3,4,5,6,7,8,9]

C++20(templates and concepts)

what is template value type?

value_type of the template is the type of template type
for example if you have std::vector<int> the value type is int like the example below …

template<typename T>
typename std::decay<typename T::value_type>::type fun2(T t){
    return *t.begin();
}

what is the “requires” keyword?

in before c++ 20 if you want to restrict type

template<class T>
class A{
public:
    using value_type=T;
};
template<class T>
class B:public A<T>{};
template<typename T,typename =std::enable_if_t<std::is_base_of_v<A<typename T::value_type>,T>>,
        typename =std::enable_if<is_arithmetic_v<typename T::value_type>>>
class tempClass{};
//tempClass<B<int>> correct
//tempClass<B<string>> is not correct string is not arithmetic type

but in c++20

template<typename T>
requires std::is_base_of_v<A<typename T::value_type>,T> && is_arithmetic_v<typename T::value_type>
class tempClass{};

what is the “concept” keyword?

template<class T>
concept MM=std::is_base_of_v<A<typename T::value_type>,T> && is_arithmetic_v<typename T::value_type>;


template<MM T>
class tempClass{};

//or

template<class T> requires MM<T>
class tempClass{};

C++ 20 (general subjects)

span array

void pspan(span<T> s) {
    cout << format("number of elements: {}\n", s.size());
    cout << format("size of span: {}\n", s.size_bytes());
    for(auto e : s) cout << format("{} ", e);
    cout << "\n";
}
int main() {
    int carray[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    pspan<int>(carray);
}

structure binding

int nums[] { 1, 2, 3, 4, 5 };
auto [ a, b, c, d, e ] = nums;
cout << format("{} {} {} {} {}\n", a, b, c, d, e);

array<int,5> nums { 1, 2, 3, 4, 5 };
auto [ a, b, c, d, e ] = nums;
cout << format("{} {} {} {} {}\n", a, b, c, d, e);

tuple<int, double, string> nums{ 1, 2.7, "three" };
auto [ a, b, c ] = nums;
cout << format("{} {} {}\n", a, b, c);

Initialize variables within if and switch statements

template<typename T>
const char * f(const T a) {
    return typeid(T).name();
}
int main() {
    cout << format("T is {}\n", f(47));
    cout << format("T is {}\n", f(47L));
    cout << format("T is {}\n", f(47.0));
    cout << format("T is {}\n", f("47"));
    cout << format("T is {}\n", f("47"s));
}

Use template argument deduction for simplicity and clarity

template<typename T>
const char * f(const T a) {
    return typeid(T).name();
}
int main() {
    cout << format("T is {}\n", f(47));
    cout << format("T is {}\n", f(47L));
    cout << format("T is {}\n", f(47.0));
    cout << format("T is {}\n", f("47"));
    cout << format("T is {}\n", f("47"s));
}
T is int
T is long
T is double
T is char const *

Use if constexpr to simplify compile-time decisions

template<typename T>
auto value_of(const T v) {
    if constexpr (std::is_pointer_v<T>) {
        return *v;  // dereference the pointer
    } else {
        return v;   // return the value
    }
}
int main() {
    int x{47};
    int* y{&x};
    cout << format("value is {}\n", value_of(x));  // value
    cout << format("value is {}\n", value_of(y));  
                                                // pointer
    return 0;
}

build GCC and G++

1- clone GCC repository

git clone git://gcc.gnu.org/git/gcc.git

2- add select branch

git branch -a #to list all branches
git checkout branch_name#to select wanted branch in our case it gcc-12

3- in the source folder you will find ./contrib/download_prerequisites  
execute it to download dependencies

4- call configuration https://gcc.gnu.org/install/configure.html

% mkdir objdir
% cd objdir
% srcdir/configure [options] [target]
../gcc/configure --prefix=/home/malabdali/gcc-12 --enable-languages=c,c++ --disable-multilib

if it succeded makefiles it will be generated here (objdir)
not that build results will be saved here /home/malabdali/gcc-12

5- start call make

sudo make -j 8

6- call make install

sudo make install

after install you can find folder(bin,lib,include) inside /home/malabdali/gcc-12

C++ GMock

add it to cmake

target_link_libraries (target_name gtest_main gmock_main gtest )

Matchers

MATCHER_P(M1,p,""){
return p>10;
}

TEST(TESTS,t1){
    testing::Matcher<int> m1(12);
    EXPECT_THAT(12,m1);
    EXPECT_THAT(true,M1(12));
    EXPECT_TRUE(m1.Matches(12));
    EXPECT_THAT(12,testing::AllOf(testing::Gt(0),testing::Lt(100)));
}

expect call

class A{
public:
    virtual void fun()const=0;
    virtual void fun2(int l)const=0;
};
class MockA:public A{
public:
    MOCK_METHOD(void,fun,(),(const override));
    MOCK_METHOD(void,fun2,(int),(const override));
};

using ::testing::AtLeast;                         // #1

TEST(PainterTest, CanDrawSomething) {
    MockA turtle;
    EXPECT_CALL(turtle, fun2(22))                  // #3
            .Times(2);//expect call this function twice with argument 22
    turtle.fun2(22);// #2//first call
    turtle.fun2(22);// #2// second call 
    // test passed because this function called twice
}

C++ GTest

install GTest with CMake

https://google.github.io/googletest/quickstart-cmake.html

include(FetchContent)
FetchContent_Declare(
        googletest
        URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
enable_testing()

target_link_libraries(
        target_name
        gtest_main gtest
)

first example

#include <gtest/gtest.h>
#include "random"

TEST(test1,t1){
    std::default_random_engine re(std::chrono::system_clock::now().time_since_epoch().count());
    std::uniform_int_distribution<uint8_t>rn(0,10);
    int v1=rn(re),v2=rn(re);
    EXPECT_EQ(v1,v2) << "Vectors x and y are of unequal length";
}
int main(int argc, char *argv[]) {
    testing::InitGoogleTest(&argc,argv);
    return RUN_ALL_TESTS();
}
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from test1
[ RUN      ] test1.t1
[       OK ] test1.t1 (0 ms)
[----------] 1 test from test1 (0 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[  PASSED  ] 1 test.

EXPECT AND ASSERT

  • ASSERT: Fails fast, aborting the current function.
  • EXPECT: Continues after the failure.

expect throw and death

Test Fixture

class MyTest : public ::testing::Test {

protected:
    void SetUp()override { //done before test like MyTest constructor
        val=12;
    }
    void TearDown()override{//done after test like ~MyTest

    }
    void add(){
        val+=12;
    }
    int val;
};

TEST_F(MyTest, t1) {
    add();
    EXPECT_EQ(val,66)<<string(__FILE__)+":"+string(std::to_string(__LINE__));
}

Disabling and Skipping Tests

Test Filtering

you can run it with parameters to add more options for testing
for filtering, you can add

--gtest_filter=*.f*

Parametrized Test

class LeapYearParameterizedTestFixture :public ::testing::TestWithParam<int> {
protected:
    int val;
};

TEST_P(LeapYearParameterizedTestFixture, OddYearsAreNotLeapYears) {
    val = GetParam();
    ASSERT_EQ(val,12);
}

INSTANTIATE_TEST_CASE_P(
        LeapYearTests,
        LeapYearParameterizedTestFixture,
        ::testing::Values(
                1, 711, 12, 2013
        ));