 Parent directory
Parent directory
 Makefile
Makefile
 mydistance.cpp
mydistance.cpp
CC  = g++
CXX = g++
CFLAGS   = -g -Wall
CXXFLAGS = -g -Wall -std=c++20
executables = mydistance
.PHONY: default
default: $(executables)
mydistance: mydistance.o
.PHONY: clean
clean:
	rm -f *~ a.out core *.o $(executables)
.PHONY: all
all: clean default#include <vector>
#include <forward_list>
#include <iostream>
#include <iterator>
using namespace std;
namespace c2cpp_simple {
    template <typename I>
    size_t MyDistance(I b, I e) {
        return e - b;
    }
}
namespace c2cpp_tag_dispatch {
    template <typename I>
    size_t __doMyDistance(I b, I e, random_access_iterator_tag) {
        return e - b;
    }
    template <typename I>
    size_t __doMyDistance(I b, I e, forward_iterator_tag) {
        size_t n = 0;
        while (b != e) {
            ++n;
            ++b;
        }
        return n;
    }
    template <typename I>
    size_t MyDistance(I b, I e) {
        return __doMyDistance(b, e, typename I::iterator_category{});
        // return __doMyDistance(b, e,
        //              typename iterator_traits<I>::iterator_category{});
    }
}
namespace c2cpp_sfinae {
    template <typename I>
    std::enable_if<is_same_v<random_access_iterator_tag,
          typename iterator_traits<I>::iterator_category>, size_t>::type
    MyDistance(I b, I e) {
        return e - b;
    }
    template <typename I>
    std::enable_if<is_same_v<forward_iterator_tag,
          typename iterator_traits<I>::iterator_category>, size_t>::type
    MyDistance(I b, I e) {
        size_t n = 0;
        while (b != e) {
            ++n;
            ++b;
        }
        return n;
    }
}
namespace c2cpp_constexpr {
    template <typename I>
    size_t MyDistance(I b, I e) {
        if constexpr (is_base_of_v<random_access_iterator_tag,
                          typename iterator_traits<I>::iterator_category>) {
            return e - b;
        } else {
            size_t n = 0;
            while (b != e) {
                ++n;
                ++b;
            }
            return n;
        } 
    }
}
namespace c2cpp_concept {
    // template <random_access_iterator I>
    template <typename I>
        requires random_access_iterator<I>
    typename iterator_traits<I>::difference_type MyDistance(I b, I e) {
        return e - b;
    }
    // template <forward_iterator I>
    template <typename I>
        requires forward_iterator<I>
    typename iterator_traits<I>::difference_type MyDistance(I b, I e) {
        size_t n = 0;
        while (b != e) {
            ++n;
            ++b;
        }
        return n;
    }
    template <typename I>
    concept MyBidirectionalIterator =
        forward_iterator<I> &&
        derived_from<typename iterator_traits<I>::iterator_category,
                              bidirectional_iterator_tag> &&
        requires (I i) {
            { ++i } -> std::same_as<I&>;
            { i++ } -> std::same_as<I>;
            { --i } -> std::same_as<I&>;
            { i-- } -> std::same_as<I>;
        };
}
int main() {
    // 1. Simply assuming random access iterator
    //
    using namespace c2cpp_simple;
    vector v { 100, 101, 102, 103, 104 };
    // forward_list v { 100, 101, 102, 103, 104 };
    // int v[5] { 100, 101, 102, 103, 104 };
    // 2. Tag dispatching
    //
    // using namespace c2cpp_tag_dispatch;
    // vector v { 100, 101, 102, 103, 104 };
    // forward_list v { 100, 101, 102, 103, 104 };
    // int v[5] { 100, 101, 102, 103, 104 };
    // 3. SFINAE
    //
    // using namespace c2cpp_sfinae;
    // vector v { 100, 101, 102, 103, 104 };
    // forward_list v { 100, 101, 102, 103, 104 };
    // int v[5] { 100, 101, 102, 103, 104 };
    // 4. if constexpr
    //
    // using namespace c2cpp_constexpr;
    // vector v { 100, 101, 102, 103, 104 };
    // forward_list v { 100, 101, 102, 103, 104 };
    // int v[5] { 100, 101, 102, 103, 104 };
    // cout << MyDistance("AAA"s, "BBB"s) << '\n';
    // 5. Using concepts to constrain type parameters
    //
    // using namespace c2cpp_concept;
    // vector v { 100, 101, 102, 103, 104 };
    // forward_list v { 100, 101, 102, 103, 104 };
    // int v[5] { 100, 101, 102, 103, 104 };
    // cout << MyDistance("AAA"s, "BBB"s) << '\n';
    auto b = ranges::begin(v);
    auto e = ranges::end(v);
    cout << "Number of elements: " << MyDistance(b, e) << '\n';
    // 6. Using concepts to constrain auto
    //
    // random_access_iterator auto b = ranges::begin(v);
    // random_access_iterator auto e = ranges::end(v);
    // cout << "Number of elements: " << MyDistance(b, e) << '\n';
    // 7. Defining a concept
    //
    // MyBidirectionalIterator auto b = ranges::begin(v);
    // MyBidirectionalIterator auto e = ranges::end(v);
    // cout << "Number of elements: " << MyDistance(b, e) << '\n';
}