template <typename T>
bool has_close_elements(T numbers, float threshold) {
  for (int i = 0; i < numbers.size(); i++)
    for (int j = i + 1; j < numbers.size(); j++)
      if (std::abs(numbers[i] - numbers[j]) < threshold)
        return true;

  return false;
}

Make the following function generic for the parameter `numbers`.

template <typename T>
  requires std::same_as<typename T::value_type, float>
bool has_close_elements(T numbers, float threshold) {
  for (int i = 0; i < numbers.size(); i++)
    for (int j = i + 1; j < numbers.size(); j++)
      if (std::abs(numbers[i] - numbers[j]) < threshold)
        return true;

  return false;
}

Constrain the generic code using C++20 Concepts so that it accepts a container with value type of floats.

int main() {
  std::string s{};
  has_close_elements(s, 3.4);
}

template <
    typename T,
    std::enable_if_t<std::is_same_v<typename T::value_type, float>, int> = 0>
bool has_close_elements(T numbers, float threshold) {
  for (int i = 0; i < numbers.size(); i++)
    for (int j = i + 1; j < numbers.size(); j++)
      if (std::abs(numbers[i] - numbers[j]) < threshold)
        return true;

  return false;
}

Constrain the generic code using C++17 SFINAE so that it accepts a container with value type of floats.

bool has_close_elements(std::vector<float> numbers, float threshold) {
  for (int i = 0; i < numbers.size(); i++)
    for (int j = i + 1; j < numbers.size(); j++)
      if (std::abs(numbers[i] - numbers[j]) < threshold)
        return true;

  return false;
}

#define ASSERT(...)                                                            \
  do {                                                                         \
    if (!(__VA_ARGS__)) {                                                      \
      std::exit(-1);                                                           \
    }                                                                          \
  } while (false)

#define TEST_ON_TYPE(_type_)                                                   \
  do {                                                                         \
    _type_ a = {1.0, 2.0, 3.9, 4.0, 5.0, 2.2};                                 \
    ASSERT(has_close_elements(a, 0.3) == true);                                \
    ASSERT(has_close_elements(a, 0.05) == false);                              \
    ASSERT(has_close_elements(_type_{1.0, 2.0, 5.9, 4.0, 5.0}, 0.95) == true); \
    ASSERT(has_close_elements(_type_{1.0, 2.0, 5.9, 4.0, 5.0}, 0.8) == false); \
    ASSERT(has_close_elements(_type_{1.0, 2.0, 3.0, 4.0, 5.0}, 2.0) == true);  \
    ASSERT(has_close_elements(_type_{1.1, 2.2, 3.1, 4.1, 5.1}, 1.0) == true);  \
    ASSERT(has_close_elements(_type_{1.1, 2.2, 3.1, 4.1, 5.1}, 0.5) == false); \
  } while (false)

int main() {
  TEST_ON_TYPE(std::vector<float>);
  TEST_ON_TYPE(std::deque<float>);
}


template <typename InputStr>
std::vector<std::string> separate_paren_groups(InputStr paren_string) {
  std::vector<std::string> all_parens;
  std::string current_paren;
  int level = 0;
  for (int i = 0; i < paren_string.size(); i++) {
    char chr = paren_string[i];
    if (chr == '(') {
      level += 1;
      current_paren += chr;
    }
    if (chr == ')') {
      level -= 1;
      current_paren += chr;
      if (level == 0) {
        all_parens.push_back(current_paren);
        current_paren = "";
      }
    }
  }
  return all_parens;
}

Make the following function generic for the parameter `paren_string`.

template <typename InputStr>
  requires requires(const InputStr& s, std::size_t i) {
    { s[i] } -> std::convertible_to<char>;
    { s.size() } -> std::convertible_to<int>;
    std::same_as<typename InputStr::value_type, char>;
  }
std::vector<std::string> separate_paren_groups(InputStr paren_string) {
  std::vector<std::string> all_parens;
  std::string current_paren;
  int level = 0;
  for (int i = 0; i < paren_string.length(); i++) {
    char chr = paren_string[i];
    if (chr == '(') {
      level += 1;
      current_paren += chr;
    }
    if (chr == ')') {
      level -= 1;
      current_paren += chr;
      if (level == 0) {
        all_parens.push_back(current_paren);
        current_paren = "";
      }
    }
  }
  return all_parens;
}

Constrain the generic code using C++20 Concepts so that the parameter `paren_string` must be a sequenced container of characters like a string.

int main() {
  float v = 3;
  separate_paren_groups(v);
}

template <
    typename InputStr,
    std::enable_if_t<
        std::conjunction_v<
            std::is_same<char, typename InputStr::value_type>,
            std::is_same<char, std::decay_t<decltype(std::declval<
                                                     InputStr>()[std::declval<
                                   std::size_t>()])>>>,
        int> = 0>
std::vector<std::string> separate_paren_groups(InputStr paren_string) {
  std::vector<std::string> all_parens;
  std::string current_paren;
  int level = 0;
  for (int i = 0; i < paren_string.size(); i++) {
    char chr = paren_string[i];
    if (chr == '(') {
      level += 1;
      current_paren += chr;
    }
    if (chr == ')') {
      level -= 1;
      current_paren += chr;
      if (level == 0) {
        all_parens.push_back(current_paren);
        current_paren = "";
      }
    }
  }
  return all_parens;
}

Constrain the generic code using C++17 SFINAE so that the parameter `paren_string` must be a sequenced container of characters like a string.

std::vector<std::string> separate_paren_groups(std::string paren_string) {
  std::vector<std::string> all_parens;
  std::string current_paren;
  int level = 0;
  for (int i = 0; i < paren_string.length(); i++) {
    char chr = paren_string[i];
    if (chr == '(') {
      level += 1;
      current_paren += chr;
    }
    if (chr == ')') {
      level -= 1;
      current_paren += chr;
      if (level == 0) {
        all_parens.push_back(current_paren);
        current_paren = "";
      }
    }
  }
  return all_parens;
}

bool issame(std::vector<std::string> a, std::vector<std::string> b) {
  if (a.size() != b.size()) return false;
  for (int i = 0; i < a.size(); i++) {
    if (a[i] != b[i]) return false;
  }
  return true;
}

#define ASSERT(...)       \
  do {                    \
    if (!(__VA_ARGS__)) { \
      std::exit(-1);      \
    }                     \
  } while (false)

#define TEST_ON_TYPE(_type_)                                                 \
  do {                                                                       \
    ASSERT(                                                                  \
        issame(separate_paren_groups(_type_("(()()) ((())) () ((())()())")), \
               {"(()())", "((()))", "()", "((())()())"}));                   \
    ASSERT(issame(separate_paren_groups(_type_("() (()) ((())) (((())))")),  \
                  {"()", "(())", "((()))", "(((())))"}));                    \
    ASSERT(issame(separate_paren_groups(_type_("(()(())((())))")),           \
                  {"(()(())((())))"}));                                      \
    ASSERT(issame(separate_paren_groups(_type_("( ) (( )) (( )( ))")),       \
                  {"()", "(())", "(()())"}));                                \
  } while (false)

int main() {
  TEST_ON_TYPE(std::string);
  TEST_ON_TYPE(std::string_view);
}


template <typename Float>
Float truncate_number(Float number) {
  return number - (long long)(number);
}

Make the following function generic for the parameter `number` and return value.

template <std::floating_point Float>
Float truncate_number(Float number) {
  return number - (long long)(number);
}

Constrain the generic code using C++20 Concepts so that the generate parameter is only floating point types.

template <typename Float,
          std::enable_if_t<std::is_floating_point_v<Float>, int> = 0>
Float truncate_number(Float number) {
  return number - (long long)(number);
}

Constrain the generic code using C++17 SFINAE so that the generate parameter is only floating point types.

float truncate_number(float number) { return number - (long long)(number); }

#define ASSERT(...)       \
  do {                    \
    if (!(__VA_ARGS__)) { \
      std::exit(-1);      \
    }                     \
  } while (false)

#define TEST_ON_TYPE(_type_)                                                  \
  do {                                                                        \
    ASSERT(truncate_number((_type_)3.5) == (_type_)0.5);                      \
    ASSERT(abs(truncate_number((_type_)1.33) - (_type_)0.33) < (_type_)1e-4); \
    ASSERT(abs(truncate_number((_type_)123.456) - (_type_)0.456) <            \
           (_type_)1e-4);                                                     \
                                                                              \
  } while (false)

int main() {
  TEST_ON_TYPE(float);
  TEST_ON_TYPE(double);
}


template <typename T>
bool below_zero(std::vector<T> operations) {
  T num = 0;
  for (int i = 0; i < operations.size(); i++) {
    num += operations[i];
    if (num < 0) return true;
  }
  return false;
}

Make the following function generic for the value type of the vector parameter `operations`.

template <typename T>
  requires std::integral<T> || std::floating_point<T>
bool below_zero(std::vector<T> operations) {
  T num = 0;
  for (int i = 0; i < operations.size(); i++) {
    num += operations[i];
    if (num < 0) return true;
  }
  return false;
}

Constrain the generic code using C++20 Concepts so that the value type of the vector is only number types.

int main() { below_zero(std::vector<int*>{}); }

template <typename T,
          std::enable_if_t<std::disjunction_v<std::is_integral<T>,
                                              std::is_floating_point<T>>,
                           int> = 0>
bool below_zero(std::vector<T> operations) {
  T num = 0;
  for (int i = 0; i < operations.size(); i++) {
    num += operations[i];
    if (num < 0) return true;
  }
  return false;
}

Constrain the generic code using C++17 SFINAE so that the value type of the vector is only number types.

bool below_zero(std::vector<int> operations) {
  int num = 0;
  for (int i = 0; i < operations.size(); i++) {
    num += operations[i];
    if (num < 0) return true;
  }
  return false;
}

#define ASSERT(...)       \
  do {                    \
    if (!(__VA_ARGS__)) { \
      std::exit(-1);      \
    }                     \
  } while (false)

#define TEST_ON_TYPE(_type_)                                              \
  do {                                                                    \
    ASSERT(below_zero(std::vector<_type_>{}) == false);                   \
    ASSERT(below_zero(std::vector<_type_>{1, 2, -3, 1, 2, -3}) == false); \
    ASSERT(below_zero(std::vector<_type_>{1, 2, -4, 5, 6}) == true);      \
    ASSERT(below_zero(std::vector<_type_>{1, -1, 2, -2, 5, -5, 4, -4}) == \
           false);                                                        \
    ASSERT(below_zero(std::vector<_type_>{1, -1, 2, -2, 5, -5, 4, -5}) == \
           true);                                                         \
    ASSERT(below_zero(std::vector<_type_>{1, -2, 2, -2, 5, -5, 4, -4}) == \
           true);                                                         \
                                                                          \
  } while (false)

int main() {
  TEST_ON_TYPE(int);
  TEST_ON_TYPE(char);
  TEST_ON_TYPE(float);
}


template <typename T>
T mean_absolute_deviation(std::vector<T> numbers) {
  T sum = 0;
  for (int i = 0; i < numbers.size(); i++) sum += numbers[i];
  T avg = sum / numbers.size();
  T msum = 0;
  for (int i = 0; i < numbers.size(); i++) msum += std::abs(numbers[i] - avg);
  return msum / numbers.size();
}

Make the following function generic for the value type of the vector parameter `numbers`.

template <std::floating_point T>
T mean_absolute_deviation(std::vector<T> numbers) {
  T sum = 0;
  for (int i = 0; i < numbers.size(); i++) sum += numbers[i];
  T avg = sum / numbers.size();
  T msum = 0;
  for (int i = 0; i < numbers.size(); i++) msum += std::abs(numbers[i] - avg);
  return msum / numbers.size();
}

Constrain the generic code using C++20 Concepts so that the generic type is only floating point types.

int main() { mean_absolute_deviation(std::vector<int>{0, 1, 2}); }

template <typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
T mean_absolute_deviation(std::vector<T> numbers) {
  T sum = 0;
  for (int i = 0; i < numbers.size(); i++) sum += numbers[i];
  T avg = sum / numbers.size();
  T msum = 0;
  for (int i = 0; i < numbers.size(); i++) msum += std::abs(numbers[i] - avg);
  return msum / numbers.size();
}

Constrain the generic code using C++17 SFINAE so that the generic type is only floating point types.

float mean_absolute_deviation(std::vector<float> numbers) {
  float sum = 0;
  for (int i = 0; i < numbers.size(); i++) sum += numbers[i];
  float avg = sum / numbers.size();
  float msum = 0;
  for (int i = 0; i < numbers.size(); i++) msum += std::abs(numbers[i] - avg);
  return msum / numbers.size();
}

#define ASSERT(...)       \
  do {                    \
    if (!(__VA_ARGS__)) { \
      std::exit(-1);      \
    }                     \
  } while (false)

#define TEST_ON_TYPE(_type_)                                                   \
  do {                                                                         \
    ASSERT(abs(mean_absolute_deviation(std::vector<_type_>{1.0, 2.0, 3.0}) -   \
               (_type_)2.0 / (_type_)3.0) < (_type_)1e-4);                     \
    ASSERT(                                                                    \
        abs(mean_absolute_deviation(std::vector<_type_>{1.0, 2.0, 3.0, 4.0}) - \
            (_type_)1.0) < (_type_)1e-4);                                      \
    ASSERT(abs(mean_absolute_deviation(                                        \
                   std::vector<_type_>{1.0, 2.0, 3.0, 4.0, 5.0}) -             \
               (_type_)6.0 / (_type_)5.0) < (_type_)1e-4);                     \
  } while (false)

int main() {
  TEST_ON_TYPE(float);
  TEST_ON_TYPE(double);
}


template <typename Container, typename Value>
Container intersperse(Container numbers, Value delimeter) {
  Container out;
  if (numbers.size() > 0) out.push_back(numbers[0]);
  for (int i = 1; i < numbers.size(); i++) {
    out.push_back(delimeter);
    out.push_back(numbers[i]);
  }
  return out;
}

Make the following function generic for both parameters and return type.

template <typename Container, typename Value>
  requires requires(Container &c, Value v) {
    { c.push_back(v) };
  }
Container intersperse(Container numbers, Value delimeter) {
  Container out;
  if (numbers.size() > 0) out.push_back(numbers[0]);
  for (int i = 1; i < numbers.size(); i++) {
    out.push_back(delimeter);
    out.push_back(numbers[i]);
  }
  return out;
}

Constrain the generic code using C++20 Concepts so that the value to intersperse can be pushed back on the container.

int main() {
  std::vector<int*> v;
  intersperse(v, int{0});
}

template <typename Container, typename Value,
          typename = std::void_t<decltype(std::declval<Container &>().push_back(
              std::declval<Value>()))>>
Container intersperse(Container numbers, Value delimeter) {
  Container out;
  if (numbers.size() > 0) out.push_back(numbers[0]);
  for (int i = 1; i < numbers.size(); i++) {
    out.push_back(delimeter);
    out.push_back(numbers[i]);
  }
  return out;
}

Constrain the generic code using C++17 SFINAE so that the value to intersperse can be pushed back on the container.

std::vector<int> intersperse(std::vector<int> numbers, int delimeter) {
  std::vector<int> out;
  if (numbers.size() > 0) out.push_back(numbers[0]);
  for (int i = 1; i < numbers.size(); i++) {
    out.push_back(delimeter);
    out.push_back(numbers[i]);
  }
  return out;
}

template <typename T>
bool issame(T a, T b) {
  if (a.size() != b.size()) return false;
  for (int i = 0; i < a.size(); i++) {
    if (a[i] != b[i]) return false;
  }
  return true;
}

#define ASSERT(...)       \
  do {                    \
    if (!(__VA_ARGS__)) { \
      std::exit(-1);      \
    }                     \
  } while (false)

#define TEST_ON_TYPE(_type_, _value_)                            \
  do {                                                           \
    ASSERT(issame(intersperse(_type_{}, (_value_)7), _type_{})); \
    ASSERT(issame(intersperse(_type_{5, 6, 3, 2}, (_value_)8),   \
                  _type_{5, 8, 6, 8, 3, 8, 2}));                 \
    ASSERT(issame(intersperse(_type_{2, 2, 2}, (_value_)2),      \
                  _type_{2, 2, 2, 2, 2}));                       \
  } while (false)

int main() {
  TEST_ON_TYPE(std::vector<int>, int);
  TEST_ON_TYPE(std::vector<float>, long);
  TEST_ON_TYPE(std::deque<float>, float);
}


template <typename T>
std::vector<int> parse_nested_parens(T paren_string) {
  std::vector<int> all_levels;
  std::string current_paren;
  int level = 0, max_level = 0;
  for (int i = 0; i < paren_string.size(); i++) {
    char chr = paren_string[i];
    if (chr == '(') {
      level += 1;
      if (level > max_level) max_level = level;
      current_paren += chr;
    }
    if (chr == ')') {
      level -= 1;
      current_paren += chr;
      if (level == 0) {
        all_levels.push_back(max_level);
        current_paren = "";
        max_level = 0;
      }
    }
  }
  return all_levels;
}

template <typename T>
  requires requires(const T& s, std::size_t i) {
    { s[i] } -> std::convertible_to<char>;
    { s.size() } -> std::convertible_to<int>;
    std::same_as<typename T::value_type, char>;
  }
std::vector<int> parse_nested_parens(T paren_string) {
  std::vector<int> all_levels;
  std::string current_paren;
  int level = 0, max_level = 0;
  for (int i = 0; i < paren_string.size(); i++) {
    char chr = paren_string[i];
    if (chr == '(') {
      level += 1;
      if (level > max_level) max_level = level;
      current_paren += chr;
    }
    if (chr == ')') {
      level -= 1;
      current_paren += chr;
      if (level == 0) {
        all_levels.push_back(max_level);
        current_paren = "";
        max_level = 0;
      }
    }
  }
  return all_levels;
}

int main() { parse_nested_parens(float{3}); }

template <
    typename T,
    std::enable_if_t<
        std::conjunction_v<
            std::is_same<char, typename T::value_type>,
            std::is_same<char,
                         std::decay_t<decltype(std::declval<T>()[std::declval<
                             std::size_t>()])>>>,
        int> = 0>
std::vector<int> parse_nested_parens(T paren_string) {
  std::vector<int> all_levels;
  std::string current_paren;
  int level = 0, max_level = 0;
  for (int i = 0; i < paren_string.length(); i++) {
    char chr = paren_string[i];
    if (chr == '(') {
      level += 1;
      if (level > max_level) max_level = level;
      current_paren += chr;
    }
    if (chr == ')') {
      level -= 1;
      current_paren += chr;
      if (level == 0) {
        all_levels.push_back(max_level);
        current_paren = "";
        max_level = 0;
      }
    }
  }
  return all_levels;
}

std::vector<int> parse_nested_parens(std::string paren_string) {
  std::vector<int> all_levels;
  std::string current_paren;
  int level = 0, max_level = 0;
  for (int i = 0; i < paren_string.size(); i++) {
    char chr = paren_string[i];
    if (chr == '(') {
      level += 1;
      if (level > max_level) max_level = level;
      current_paren += chr;
    }
    if (chr == ')') {
      level -= 1;
      current_paren += chr;
      if (level == 0) {
        all_levels.push_back(max_level);
        current_paren = "";
        max_level = 0;
      }
    }
  }
  return all_levels;
}

bool issame(std::vector<int> a, std::vector<int> b) {
  if (a.size() != b.size()) return false;
  for (int i = 0; i < a.size(); i++) {
    if (a[i] != b[i]) return false;
  }
  return true;
}

#define ASSERT(...)       \
  do {                    \
    if (!(__VA_ARGS__)) { \
      std::exit(-1);      \
    }                     \
  } while (false)

#define TEST_ON_TYPE(_type_)                                                  \
  do {                                                                        \
    ASSERT(issame(parse_nested_parens(_type_{"(()()) ((())) () ((())()())"}), \
                  {2, 3, 1, 3}));                                             \
    ASSERT(issame(parse_nested_parens(_type_{"() (()) ((())) (((())))"}),     \
                  {1, 2, 3, 4}));                                             \
    ASSERT(issame(parse_nested_parens(_type_{"(()(())((())))"}), {4}));       \
  } while (false)

int main() {
  TEST_ON_TYPE(std::string);
  TEST_ON_TYPE(std::string_view);
}


template <typename T>
T filter_by_substring(T strings, std::string substring) {
  T out;
  for (int i = 0; i < strings.size(); i++) {
    if (strings[i].find(substring) != strings[i].npos)
      out.push_back(strings[i]);
  }
  return out;
}

Make the following function generic for the parameter `string` and return value.

template <typename T>
  requires std::same_as<typename T::value_type, std::string>
T filter_by_substring(T strings, std::string substring) {
  T out;
  for (int i = 0; i < strings.size(); i++) {
    if (strings[i].find(substring) != strings[i].npos)
      out.push_back(strings[i]);
  }
  return out;
}

Constrain the generic code using C++20 Concepts so that it accepts a sequenced container with value type of string.

int main() { filter_by_substring(std::vector<int>{}, "hello"); }

template <typename T,
          std::enable_if_t<std::is_same_v<typename T::value_type, std::string>,
                           int> = 0>
T filter_by_substring(T strings, std::string substring) {
  T out;
  for (int i = 0; i < strings.size(); i++) {
    if (strings[i].find(substring) != strings[i].npos)
      out.push_back(strings[i]);
  }
  return out;
}

Constrain the generic code using C++17 SFINAE so that it accepts a sequenced container with value type of string.

std::vector<string> filter_by_substring(std::vector<string> strings,
                                        std::string substring) {
  std::vector<string> out;
  for (int i = 0; i < strings.size(); i++) {
    if (strings[i].find(substring) != strings[i].npos)
      out.push_back(strings[i]);
  }
  return out;
}

template <typename T>
bool issame(T a, T b) {
  if (a.size() != b.size()) return false;
  for (int i = 0; i < a.size(); i++) {
    if (a[i] != b[i]) return false;
  }
  return true;
}

#define ASSERT(...)       \
  do {                    \
    if (!(__VA_ARGS__)) { \
      std::exit(-1);      \
    }                     \
  } while (false)

#define TEST_ON_TYPE(_type_)                                                   \
  do {                                                                         \
    ASSERT(issame(filter_by_substring(_type_{}, "john"), _type_{}));           \
    ASSERT(issame(                                                             \
        filter_by_substring(                                                   \
            _type_{"xxx", "asd", "xxy", "john doe", "xxxAAA", "xxx"}, "xxx"),  \
        _type_{"xxx", "xxxAAA", "xxx"}));                                      \
    ASSERT(issame(filter_by_substring(_type_{"xxx", "asd", "aaaxxy",           \
                                             "john doe", "xxxAAA", "xxx"},     \
                                      "xx"),                                   \
                  _type_{"xxx", "aaaxxy", "xxxAAA", "xxx"}));                  \
    ASSERT(issame(filter_by_substring(                                         \
                      _type_{"grunt", "trumpet", "prune", "gruesome"}, "run"), \
                  _type_{"grunt", "prune"}));                                  \
  } while (false)

int main() {
  TEST_ON_TYPE(std::vector<std::string>);
  TEST_ON_TYPE(std::deque<std::string>);
}


template <typename T>
std::pair<T, T> sum_product(std::vector<T> numbers) {
  T sum = 0, product = 1;
  for (int i = 0; i < numbers.size(); i++) {
    sum += numbers[i];
    product *= numbers[i];
  }
  return {sum, product};
}

Make the following function generic for the value types of the parameter and return pair.

template <typename T>
  requires std::integral<T> || std::floating_point<T>
std::pair<T, T> sum_product(std::vector<T> numbers) {
  T sum = 0, product = 1;
  for (int i = 0; i < numbers.size(); i++) {
    sum += numbers[i];
    product *= numbers[i];
  }
  return {sum, product};
}

Constrain the generic code using C++20 Concepts so that the generic parameter is a number type.

int main() { sum_product(std::vector<int*>{}); }

template <typename T,
          std::enable_if_t<std::disjunction_v<std::is_integral<T>,
                                              std::is_floating_point<T>>,
                           int> = 0>
std::pair<T, T> sum_product(std::vector<T> numbers) {
  T sum = 0, product = 1;
  for (int i = 0; i < numbers.size(); i++) {
    sum += numbers[i];
    product *= numbers[i];
  }
  return {sum, product};
}

Constrain the generic code using C++17 SFINAE so that the generic parameter is a number type.

std::pair<int, int> sum_product(std::vector<int> numbers) {
  int sum = 0, product = 1;
  for (int i = 0; i < numbers.size(); i++) {
    sum += numbers[i];
    product *= numbers[i];
  }
  return {sum, product};
}

#define ASSERT(...)       \
  do {                    \
    if (!(__VA_ARGS__)) { \
      std::exit(-1);      \
    }                     \
  } while (false)

#define TEST_ON_TYPE(_type_)                                 \
  do {                                                       \
    ASSERT(sum_product(std::vector<_type_>{}) ==             \
           std::pair<_type_, _type_>{0, 1});                 \
    ASSERT(sum_product(std::vector<_type_>{1, 1, 1}) ==      \
           std::pair<_type_, _type_>{3, 1});                 \
    ASSERT(sum_product(std::vector<_type_>{100, 0}) ==       \
           std::pair<_type_, _type_>{100, 0});               \
    ASSERT(sum_product(std::vector<_type_>{3, 5, 7}) ==      \
           std::pair<_type_, _type_>{3 + 5 + 7, 3 * 5 * 7}); \
    ASSERT(sum_product(std::vector<_type_>{10}) ==           \
           std::pair<_type_, _type_>{10, 10});               \
  } while (false)

int main() {
  TEST_ON_TYPE(float);
  TEST_ON_TYPE(int);
  TEST_ON_TYPE(long);
}


template <typename T>
std::vector<T> rolling_max(std::vector<T> numbers) {
  if (numbers.size() == 0) return {};
  std::vector<T> out;
  T max = numbers.front();
  for (int i = 0; i < numbers.size(); i++) {
    if (numbers[i] > max) max = numbers[i];
    out.push_back(max);
  }
  return out;
}

Make the following function generic for value type of the parameter and return type.

template <typename T>
  requires requires(const T& lhs, const T& rhs) {
    { lhs > rhs } -> std::convertible_to<bool>;
  }
std::vector<T> rolling_max(std::vector<T> numbers) {
  if (numbers.size() == 0) return {};
  std::vector<T> out;
  T max = numbers.front();
  for (int i = 0; i < numbers.size(); i++) {
    if (numbers[i] > max) max = numbers[i];
    out.push_back(max);
  }
  return out;
}

Constrain the generic code using C++20 Concepts so that the generic parameter must be comparable to another of its type with greater than operator.

int main() {
  struct S {};
  rolling_max(std::vector<S>{});
}

template <
    typename T,
    std::enable_if_t<std::is_convertible_v<decltype(std::declval<const T &>() >
                                                    std::declval<const T &>()),
                                           bool>,
                     int> = 0>
std::vector<T> rolling_max(std::vector<T> numbers) {
  if (numbers.size() == 0) return {};
  std::vector<T> out;
  T max = numbers.front();
  for (int i = 0; i < numbers.size(); i++) {
    if (numbers[i] > max) max = numbers[i];
    out.push_back(max);
  }
  return out;
}

Constrain the generic code using C++17 SFINAE so that the generic parameter must be comparable to another of its type with greater than operator.

std::vector<int> rolling_max(std::vector<int> numbers) {
  if (numbers.size() == 0) return {};
  std::vector<int> out;
  int max = numbers.front();
  for (int i = 0; i < numbers.size(); i++) {
    if (numbers[i] > max) max = numbers[i];
    out.push_back(max);
  }
  return out;
}

template <typename T>
bool issame(std::vector<T> a, std::vector<T> b) {
  if (a.size() != b.size()) return false;
  for (int i = 0; i < a.size(); i++) {
    if (a[i] != b[i]) return false;
  }
  return true;
}

#define ASSERT(...)       \
  do {                    \
    if (!(__VA_ARGS__)) { \
      std::exit(-1);      \
    }                     \
  } while (false)

#define TEST_ON_TYPE(_type_)                                                   \
  do {                                                                         \
    ASSERT(issame(rolling_max(std::vector<_type_>{}), std::vector<_type_>{})); \
    ASSERT(issame(rolling_max(std::vector<_type_>{1, 2, 3, 4}),                \
                  std::vector<_type_>{1, 2, 3, 4}));                           \
    ASSERT(issame(rolling_max(std::vector<_type_>{4, 3, 2, 1}),                \
                  std::vector<_type_>{4, 4, 4, 4}));                           \
    ASSERT(issame(rolling_max(std::vector<_type_>{3, 2, 3, 100, 3}),           \
                  std::vector<_type_>{3, 3, 3, 100, 100}));                    \
  } while (false)

int main() {
  TEST_ON_TYPE(int);
  TEST_ON_TYPE(float);

  ASSERT(issame(rolling_max(std::vector<std::string>{}),
                std::vector<std::string>{}));
  ASSERT(issame(rolling_max(std::vector<std::string>{"1", "2", "3", "4"}),
                std::vector<std::string>{"1", "2", "3", "4"}));
  ASSERT(issame(rolling_max(std::vector<std::string>{"4", "3", "2", "1"}),
                std::vector<std::string>{"4", "4", "4", "4"}));
  ASSERT(issame(rolling_max(std::vector<std::string>{"3", "2", "3", "5", "3"}),
                std::vector<std::string>{"3", "3", "3", "5", "5"}));
}


template <typename T>
std::string string_xor(T a, T b) {
  std::string output = "";
  for (int i = 0; (i < a.size() && i < b.size()); i++) {
    if (i < a.size() && i < b.size()) {
      if (a[i] == b[i]) {
        output += '0';
      } else
        output += '1';
    } else {
      if (i >= a.size()) {
        output += b[i];
      } else
        output += a[i];
    }
  }
  return output;
}

Make the following function generic for the type of the two parameters.

template <typename T>
  requires std::same_as<typename T::value_type, char>
std::string string_xor(T a, T b) {
  std::string output = "";
  for (int i = 0; (i < a.size() && i < b.size()); i++) {
    if (i < a.size() && i < b.size()) {
      if (a[i] == b[i]) {
        output += '0';
      } else
        output += '1';
    } else {
      if (i >= a.size()) {
        output += b[i];
      } else
        output += a[i];
    }
  }
  return output;
}

Constrain the generic code using C++20 Concepts so that the generic parameter is a sequenced container of characters.

int main() { string_xor(std::vector<int>{}, std::vector<int>{}); }

template <
    typename T,
    std::enable_if_t<std::is_same_v<typename T::value_type, char>, int> = 0>
std::string string_xor(T a, T b) {
  std::string output = "";
  for (int i = 0; (i < a.size() && i < b.size()); i++) {
    if (i < a.size() && i < b.size()) {
      if (a[i] == b[i]) {
        output += '0';
      } else
        output += '1';
    } else {
      if (i >= a.size()) {
        output += b[i];
      } else
        output += a[i];
    }
  }
  return output;
}

Constrain the generic code using C++17 SFINAE so that the generic parameter is a sequenced container of characters.

std::string string_xor(std::string a, std::string b) {
  std::string output = "";
  for (int i = 0; (i < a.size() && i < b.size()); i++) {
    if (i < a.size() && i < b.size()) {
      if (a[i] == b[i]) {
        output += '0';
      } else
        output += '1';
    } else {
      if (i >= a.size()) {
        output += b[i];
      } else
        output += a[i];
    }
  }
  return output;
}


template <typename T>
std::string longest(T strings) {
  std::string out;
  for (int i = 0; i < strings.size(); i++) {
    if (strings[i].length() > out.length()) out = strings[i];
  }
  return out;
}

Make the following function generic for the container parameter `strings`.

template <typename T>
  requires std::same_as<typename T::value_type, std::string>
std::string longest(T strings) {
  std::string out;
  for (int i = 0; i < strings.size(); i++) {
    if (strings[i].length() > out.length()) out = strings[i];
  }
  return out;
}

Constrain the generic code using C++20 Concepts so that the generic parameter is a sequenced container of value type string.

int main() { longest(std::vector<int>{}) }

template <typename T,
          std::enable_if_t<std::is_same_v<typename T::value_type, std::string>,
                           int> = 0>
std::string longest(T strings) {
  std::string out;
  for (int i = 0; i < strings.size(); i++) {
    if (strings[i].length() > out.length()) out = strings[i];
  }
  return out;
}

Constrain the generic code using C++17 SFINAE so that the generic parameter is a sequenced container of value type string.

std::string longest(std::vector<std::string> strings) {
  std::string out;
  for (int i = 0; i < strings.size(); i++) {
    if (strings[i].length() > out.length()) out = strings[i];
  }
  return out;
}

#define ASSERT(...)       \
  do {                    \
    if (!(__VA_ARGS__)) { \
      std::exit(-1);      \
    }                     \
  } while (false)

#define TEST_ON_TYPE(_type_)                                            \
  do {                                                                  \
    ASSERT(longest(_type_{}) == "");                                    \
    ASSERT(longest(_type_{"x", "y", "z"}) == "x");                      \
    ASSERT(longest(_type_{"x", "yyy", "zzzz", "www", "kkkk", "abc"}) == \
           "zzzz");                                                     \
                                                                        \
  } while (false)

int main() {
  TEST_ON_TYPE(std::vector<std::string>);
  TEST_ON_TYPE(std::deque<std::string>);
}


template <typename T>
T greatest_common_divisor(T a, T b) {
  T out, m;
  while (true) {
    if (a < b) {
      m = a;
      a = b;
      b = m;
    }
    a = a % b;
    if (a == 0) return b;
  }
}

Make the following function generic to share same type for all parameters and return type.

template <std::integral T>
T greatest_common_divisor(T a, T b) {
  T out, m;
  while (true) {
    if (a < b) {
      m = a;
      a = b;
      b = m;
    }
    a = a % b;
    if (a == 0) return b;
  }
}

Constrain the generic code using C++20 Concepts so that the generic parameter is an integer type.

int main() { greatest_common_divisor(3.0, 4.0); }

template <typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
T greatest_common_divisor(T a, T b) {
  T out, m;
  while (true) {
    if (a < b) {
      m = a;
      a = b;
      b = m;
    }
    a = a % b;
    if (a == 0) return b;
  }
}

Constrain the generic code using C++17 SFINAE so that the generic parameter is an integer type.

int greatest_common_divisor(int a, int b) {
  int out, m;
  while (true) {
    if (a < b) {
      m = a;
      a = b;
      b = m;
    }
    a = a % b;
    if (a == 0) return b;
  }
}

#define ASSERT(...)       \
  do {                    \
    if (!(__VA_ARGS__)) { \
      std::exit(-1);      \
    }                     \
  } while (false)

#define TEST_ON_TYPE(_type_)                                                \
  do {                                                                      \
    ASSERT(greatest_common_divisor((_type_)3, (_type_)7) == (_type_)1);     \
    ASSERT(greatest_common_divisor((_type_)10, (_type_)15) == (_type_)5);   \
    ASSERT(greatest_common_divisor((_type_)49, (_type_)14) == (_type_)7);   \
    ASSERT(greatest_common_divisor((_type_)144, (_type_)60) == (_type_)12); \
                                                                            \
  } while (false)

int main() {
  TEST_ON_TYPE(int);
  TEST_ON_TYPE(long);
  TEST_ON_TYPE(long long);
}


template <typename T>
std::vector<std::string> all_prefixes(T str) {
  std::vector<std::string> out;
  std::string current = "";
  for (int i = 0; i < str.size(); i++) {
    current = current + str[i];
    out.push_back(current);
  }
  return out;
}

Make the following function generic for the parameter `str`.

template <typename T>
  requires requires(const T& s, std::size_t i) {
    { s[i] } -> std::convertible_to<char>;
    { s.size() } -> std::convertible_to<int>;
    std::same_as<typename T::value_type, char>;
  }
std::vector<std::string> all_prefixes(T str) {
  std::vector<std::string> out;
  std::string current = "";
  for (int i = 0; i < str.size(); i++) {
    current = current + str[i];
    out.push_back(current);
  }
  return out;
}

Constrain the generic code using C++20 Concepts so that the generic type is a sequenced container of characters like a string.

int main() { all_prefixes(std::vector<int>{}); }

template <
    typename T,
    std::enable_if_t<
        std::conjunction_v<
            std::is_same<char, typename T::value_type>,
            std::is_same<char,
                         std::decay_t<decltype(std::declval<T>()[std::declval<
                             std::size_t>()])>>>,
        int> = 0>
std::vector<std::string> all_prefixes(T str) {
  std::vector<std::string> out;
  std::string current = "";
  for (int i = 0; i < str.size(); i++) {
    current = current + str[i];
    out.push_back(current);
  }
  return out;
}

Constrain the generic code using C++17 SFINAE so that the generic type is a sequenced container of characters like a string.

std::vector<std::string> all_prefixes(std::string str) {
  std::vector<std::string> out;
  std::string current = "";
  for (int i = 0; i < str.size(); i++) {
    current = current + str[i];
    out.push_back(current);
  }
  return out;
}

bool issame(std::vector<std::string> a, std::vector<std::string> b) {
  if (a.size() != b.size()) return false;
  for (int i = 0; i < a.size(); i++) {
    if (a[i] != b[i]) return false;
  }
  return true;
}

#define ASSERT(...)       \
  do {                    \
    if (!(__VA_ARGS__)) { \
      std::exit(-1);      \
    }                     \
  } while (false)

#define TEST_ON_TYPE(_type_)                                         \
  do {                                                               \
    ASSERT(issame(all_prefixes(_type_{""}), {}));                    \
    ASSERT(issame(all_prefixes(_type_{"asdfgh"}),                    \
                  {"a", "as", "asd", "asdf", "asdfg", "asdfgh"}));   \
    ASSERT(issame(all_prefixes(_type_{"WWW"}), {"W", "WW", "WWW"})); \
                                                                     \
  } while (false)

int main() {
  TEST_ON_TYPE(std::string);
  TEST_ON_TYPE(std::string_view);
}


template <typename T>
std::string string_sequence(T n) {
  std::string out = "0";
  for (T i = 1; i <= n && i != 0; i++) out = out + " " + std::to_string(i);
  return out;
}

Make the following function generic for the parameter `n`.

template <std::unsigned_integral T>
std::string string_sequence(T n) {
  std::string out = "0";
  for (T i = 1; i <= n && i != 0; i++) out = out + " " + std::to_string(i);
  return out;
}

Constrain the generic code using C++20 Concepts so that the generic parameter is an unsigned number.

template <typename T, std::enable_if_t<std::is_unsigned_v<T>, int> = 0>
std::string string_sequence(T n) {
  std::string out = "0";
  for (T i = 1; i <= n && i != 0; i++) out = out + " " + std::to_string(i);
  return out;
}

Constrain the generic code using C++17 SFINAE so that the generic parameter is an unsigned number.

std::string string_sequence(unsigned n) {
  std::string out = "0";
  for (unsigned i = 1; i <= n && i != 0; i++)
    out = out + " " + std::to_string(i);
  return out;
}

#define ASSERT(...)       \
  do {                    \
    if (!(__VA_ARGS__)) { \
      std::exit(-1);      \
    }                     \
  } while (false)

#define TEST_ON_TYPE(_type_)                                         \
  do {                                                               \
    ASSERT(string_sequence((_type_)0) == "0");                       \
    ASSERT(string_sequence((_type_)3) == "0 1 2 3");                 \
    ASSERT(string_sequence((_type_)10) == "0 1 2 3 4 5 6 7 8 9 10"); \
                                                                     \
  } while (false)

int main() {
  TEST_ON_TYPE(unsigned long);
  TEST_ON_TYPE(unsigned int);
}


template <typename T>
int count_distinct_characters(T str) {
  std::vector<char> distinct = {};
  std::transform(str.begin(), str.end(), str.begin(), ::tolower);
  for (int i = 0; i < str.size(); i++) {
    bool isin = false;
    for (int j = 0; j < distinct.size(); j++)
      if (distinct[j] == str[i]) isin = true;
    if (isin == false) distinct.push_back(str[i]);
  }
  return distinct.size();
}

template <typename T>
  requires std::same_as<typename T::value_type, char>
int count_distinct_characters(T str) {
  std::vector<char> distinct = {};
  std::transform(str.begin(), str.end(), str.begin(), ::tolower);
  for (int i = 0; i < str.size(); i++) {
    bool isin = false;
    for (int j = 0; j < distinct.size(); j++)
      if (distinct[j] == str[i]) isin = true;
    if (isin == false) distinct.push_back(str[i]);
  }
  return distinct.size();
}

Constrain the generic code using C++20 Concepts so that the generic parameter is a sequenced container of value type character.

int main() { count_distinct_characters(std::vector<int>{}); }

template <
    typename T,
    std::enable_if_t<std::is_same_v<typename T::value_type, char>, int> = 0>
int count_distinct_characters(T str) {
  std::vector<char> distinct = {};
  std::transform(str.begin(), str.end(), str.begin(), ::tolower);
  for (int i = 0; i < str.size(); i++) {
    bool isin = false;
    for (int j = 0; j < distinct.size(); j++)
      if (distinct[j] == str[i]) isin = true;
    if (isin == false) distinct.push_back(str[i]);
  }
  return distinct.size();
}

Constrain the generic code using C++17 SFINAE so that the generic parameter is a sequenced container of value type character.

int count_distinct_characters(std::string str) {
  std::vector<char> distinct = {};
  std::transform(str.begin(), str.end(), str.begin(), ::tolower);
  for (int i = 0; i < str.size(); i++) {
    bool isin = false;
    for (int j = 0; j < distinct.size(); j++)
      if (distinct[j] == str[i]) isin = true;
    if (isin == false) distinct.push_back(str[i]);
  }
  return distinct.size();
}

#define ASSERT(...)       \
  do {                    \
    if (!(__VA_ARGS__)) { \
      std::exit(-1);      \
    }                     \
  } while (false)

int main() {
  ASSERT(count_distinct_characters(std::string{""}) == 0);
  ASSERT(count_distinct_characters(std::string{"abcde"}) == 5);
  ASSERT(count_distinct_characters(std::string{"abcdecadeCADE"}) == 5);
  ASSERT(count_distinct_characters(std::string{"aaaaAAAAaaaa"}) == 1);
  ASSERT(count_distinct_characters(std::string{"Jerry jERRY JeRRRY"}) == 5);

  ASSERT(count_distinct_characters(std::vector<char>{}) == 0);
  ASSERT(count_distinct_characters(
             std::vector<char>{'a', 'b', 'c', 'd', 'e'}) == 5);
  ASSERT(count_distinct_characters(std::vector<char>{'a', 'b', 'c', 'd', 'e',
                                                     'c', 'a', 'd', 'e', 'C',
                                                     'A', 'D', 'E'}) == 5);
  ASSERT(count_distinct_characters(std::vector<char>{
             'a', 'a', 'a', 'a', 'A', 'A', 'A', 'A', 'a', 'a', 'a', 'a'}) == 1);
  ASSERT(count_distinct_characters(
             std::vector<char>{'J', 'e', 'r', 'r', 'y', ' ', 'j', 'E', 'R', 'R',
                               'Y', ' ', 'J', 'e', 'R', 'R', 'R', 'Y'}) == 5);
}


template <typename T>
T parse_music(std::string music_string) {
  std::string current = "";
  T out = {};
  if (music_string.size() > 0) music_string = music_string + ' ';
  for (int i = 0; i < music_string.length(); i++) {
    if (music_string[i] == ' ') {
      if (current == "o") out.push_back(4);
      if (current == "o|") out.push_back(2);
      if (current == ".|") out.push_back(1);
      current = "";
    } else
      current += music_string[i];
  }
  return out;
}

Make the following function generic for the return type.

template <typename T>
  requires requires(T& t, int v) {
    { t.push_back(v) };
  }
T parse_music(std::string music_string) {
  std::string current = "";
  T out = {};
  if (music_string.size() > 0) music_string = music_string + ' ';
  for (int i = 0; i < music_string.length(); i++) {
    if (music_string[i] == ' ') {
      if (current == "o") out.push_back(4);
      if (current == "o|") out.push_back(2);
      if (current == ".|") out.push_back(1);
      current = "";
    } else
      current += music_string[i];
  }
  return out;
}

Constrain the generic code using C++20 Concepts so that the generic parameter is a container of int that can be pushed back into.

template <typename T,
          typename = std::void_t<
              decltype(std::declval<T&>().push_back(std::declval<int>()))>>
T parse_music(std::string music_string) {
  std::string current = "";
  T out = {};
  if (music_string.size() > 0) music_string = music_string + ' ';
  for (int i = 0; i < music_string.length(); i++) {
    if (music_string[i] == ' ') {
      if (current == "o") out.push_back(4);
      if (current == "o|") out.push_back(2);
      if (current == ".|") out.push_back(1);
      current = "";
    } else
      current += music_string[i];
  }
  return out;
}

Constrain the generic code using C++17 SFINAE so that the generic parameter is a container of int that can be pushed back into.

std::vector<int> parse_music(std::string music_string) {
  std::string current = "";
  std::vector<int> out = {};
  if (music_string.size() > 0) music_string = music_string + ' ';
  for (int i = 0; i < music_string.length(); i++) {
    if (music_string[i] == ' ') {
      if (current == "o") out.push_back(4);
      if (current == "o|") out.push_back(2);
      if (current == ".|") out.push_back(1);
      current = "";
    } else
      current += music_string[i];
  }
  return out;
}

template <typename T>
bool issame(T a, T b) {
  if (a.size() != b.size()) return false;
  return std::equal(a.begin(), a.end(), b.begin());
}

#define ASSERT(...)       \
  do {                    \
    if (!(__VA_ARGS__)) { \
      std::exit(-1);      \
    }                     \
  } while (false)

#define TEST_ON_TYPE(_type_)                                                \
  do {                                                                      \
    ASSERT(issame(parse_music<_type_>(""), _type_{}));                      \
    ASSERT(issame(parse_music<_type_>("o o o o"), _type_{4, 4, 4, 4}));     \
    ASSERT(issame(parse_music<_type_>(".| .| .| .|"), _type_{1, 1, 1, 1})); \
    ASSERT(issame(parse_music<_type_>("o| o| .| .| o o o o"),               \
                  _type_{2, 2, 1, 1, 4, 4, 4, 4}));                         \
    ASSERT(issame(parse_music<_type_>("o| .| o| .| o o| o o|"),             \
                  _type_{2, 1, 2, 1, 4, 2, 4, 2}));                         \
  } while (false)

int main() {
  TEST_ON_TYPE(std::vector<int>);
  TEST_ON_TYPE(std::deque<int>);
  TEST_ON_TYPE(std::list<int>);
}


template <typename T>
T how_many_times(std::string str, std::string substring) {
  T out = 0;
  if (str.length() == 0) return 0;
  for (int i = 0; i <= str.length() - substring.length(); i++)
    if (str.substr(i, substring.length()) == substring) out += 1;
  return out;
}

Make the following function generic for the return value.

template <std::integral T>
T how_many_times(std::string str, std::string substring) {
  T out = 0;
  if (str.length() == 0) return 0;
  for (int i = 0; i <= str.length() - substring.length(); i++)
    if (str.substr(i, substring.length()) == substring) out += 1;
  return out;
}

int main() { how_many_times<float>("", "x"); }

template <typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
T how_many_times(std::string str, std::string substring) {
  T out = 0;
  if (str.length() == 0) return 0;
  for (int i = 0; i <= str.length() - substring.length(); i++)
    if (str.substr(i, substring.length()) == substring) out += 1;
  return out;
}

int how_many_times(std::string str, std::string substring) {
  int out = 0;
  if (str.length() == 0) return 0;
  for (int i = 0; i <= str.length() - substring.length(); i++)
    if (str.substr(i, substring.length()) == substring) out += 1;
  return out;
}

#define ASSERT(...)       \
  do {                    \
    if (!(__VA_ARGS__)) { \
      std::exit(-1);      \
    }                     \
  } while (false)

#define TEST_ON_TYPE(_type_)                                         \
  do {                                                               \
    ASSERT(how_many_times<_type_>("", "x") == (_type_)0);            \
    ASSERT(how_many_times<_type_>("xyxyxyx", "x") == (_type_)4);     \
    ASSERT(how_many_times<_type_>("cacacacac", "cac") == (_type_)4); \
    ASSERT(how_many_times<_type_>("john doe", "john") == (_type_)1); \
                                                                     \
  } while (false)

int main() {
  TEST_ON_TYPE(int);
  TEST_ON_TYPE(unsigned);
  TEST_ON_TYPE(unsigned long long);
  TEST_ON_TYPE(short);
}


template <typename T>
std::vector<T> find_closest_elements(std::vector<T> numbers) {
  std::vector<T> out = {};
  for (int i = 0; i < numbers.size(); i++) {
    for (int j = i + 1; j < numbers.size(); j++) {
      if (out.size() == 0 ||
          std::abs(numbers[i] - numbers[j]) < std::abs(out[0] - out[1])) {
        out = {numbers[i], numbers[j]};
      }
    }
  }
  if (out[0] > out[1]) {
    out = {out[1], out[0]};
  }
  return out;
}

Make the following function generic for the value type of the vector parameter and vector return value.

template <std::floating_point T>
std::vector<T> find_closest_elements(std::vector<T> numbers) {
  std::vector<T> out = {};
  for (int i = 0; i < numbers.size(); i++) {
    for (int j = i + 1; j < numbers.size(); j++) {
      if (out.size() == 0 ||
          std::abs(numbers[i] - numbers[j]) < std::abs(out[0] - out[1])) {
        out = {numbers[i], numbers[j]};
      }
    }
  }
  if (out[0] > out[1]) {
    out = {out[1], out[0]};
  }
  return out;
}

Constrain the generic code using C++20 Concepts so that the generic parameter is a floating point type.

int main() { find_closest_elements(std::vector<int>{1, 2, 3, 4, 5}); }

template <typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
std::vector<T> find_closest_elements(std::vector<T> numbers) {
  std::vector<T> out = {};
  for (int i = 0; i < numbers.size(); i++) {
    for (int j = i + 1; j < numbers.size(); j++) {
      if (out.size() == 0 ||
          std::abs(numbers[i] - numbers[j]) < std::abs(out[0] - out[1])) {
        out = {numbers[i], numbers[j]};
      }
    }
  }
  if (out[0] > out[1]) {
    out = {out[1], out[0]};
  }
  return out;
}

Constrain the generic code using C++17 SFINAE so that the generic parameter is a floating point type.

std::vector<float> find_closest_elements(std::vector<float> numbers) {
  std::vector<float> out = {};
  for (int i = 0; i < numbers.size(); i++) {
    for (int j = i + 1; j < numbers.size(); j++) {
      if (out.size() == 0 ||
          std::abs(numbers[i] - numbers[j]) < std::abs(out[0] - out[1])) {
        out = {numbers[i], numbers[j]};
      }
    }
  }
  if (out[0] > out[1]) {
    out = {out[1], out[0]};
  }
  return out;
}

template <typename T>
bool issame(std::vector<T> a, std::vector<T> b) {
  if (a.size() != b.size()) return false;
  for (int i = 0; i < a.size(); i++) {
    if (std::abs(a[i] - b[i]) > 1e-4) return false;
  }
  return true;
}

#define ASSERT(...)       \
  do {                    \
    if (!(__VA_ARGS__)) { \
      std::exit(-1);      \
    }                     \
  } while (false)

#define TEST_ON_TYPE(_type_)                                                   \
  do {                                                                         \
    ASSERT(issame(find_closest_elements(_type_{1.0, 2.0, 3.9, 4.0, 5.0, 2.2}), \
                  _type_{3.9, 4.0}));                                          \
    ASSERT(issame(find_closest_elements(_type_{1.0, 2.0, 5.9, 4.0, 5.0}),      \
                  _type_{5.0, 5.9}));                                          \
    ASSERT(issame(find_closest_elements(_type_{1.0, 2.0, 3.0, 4.0, 5.0, 2.2}), \
                  _type_{2.0, 2.2}));                                          \
    ASSERT(issame(find_closest_elements(_type_{1.0, 2.0, 3.0, 4.0, 5.0, 2.0}), \
                  _type_{2.0, 2.0}));                                          \
    ASSERT(issame(find_closest_elements(_type_{1.1, 2.2, 3.1, 4.1, 5.1}),      \
                  _type_{2.2, 3.1}));                                          \
                                                                               \
  } while (false)

int main() {
  TEST_ON_TYPE(std::vector<float>);
  TEST_ON_TYPE(std::vector<double>);
}


template <typename T>
std::vector<T> rescale_to_unit(std::vector<T> numbers) {
  T min = 100000, max = -100000;
  for (int i = 0; i < numbers.size(); i++) {
    if (numbers[i] < min) min = numbers[i];
    if (numbers[i] > max) max = numbers[i];
  }
  for (int i = 0; i < numbers.size(); i++)
    numbers[i] = (numbers[i] - min) / (max - min);
  return numbers;
}

template <std::floating_point T>
std::vector<T> rescale_to_unit(std::vector<T> numbers) {
  T min = 100000, max = -100000;
  for (int i = 0; i < numbers.size(); i++) {
    if (numbers[i] < min) min = numbers[i];
    if (numbers[i] > max) max = numbers[i];
  }
  for (int i = 0; i < numbers.size(); i++)
    numbers[i] = (numbers[i] - min) / (max - min);
  return numbers;
}

int main() { rescale_to_unit(std::vector<int>{1, 2, 3}); }

template <typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
std::vector<T> rescale_to_unit(std::vector<T> numbers) {
  T min = 100000, max = -100000;
  for (int i = 0; i < numbers.size(); i++) {
    if (numbers[i] < min) min = numbers[i];
    if (numbers[i] > max) max = numbers[i];
  }
  for (int i = 0; i < numbers.size(); i++)
    numbers[i] = (numbers[i] - min) / (max - min);
  return numbers;
}

std::vector<float> rescale_to_unit(std::vector<float> numbers) {
  float min = 100000, max = -100000;
  for (int i = 0; i < numbers.size(); i++) {
    if (numbers[i] < min) min = numbers[i];
    if (numbers[i] > max) max = numbers[i];
  }
  for (int i = 0; i < numbers.size(); i++)
    numbers[i] = (numbers[i] - min) / (max - min);
  return numbers;
}

template <typename T>
bool issame(std::vector<T> a, std::vector<T> b) {
  if (a.size() != b.size()) return false;
  for (int i = 0; i < a.size(); i++) {
    if (std::abs(a[i] - b[i]) > 1e-4) return false;
  }
  return true;
}

#define ASSERT(...)       \
  do {                    \
    if (!(__VA_ARGS__)) { \
      std::exit(-1);      \
    }                     \
  } while (false)

#define TEST_ON_TYPE(_type_)                                                \
  do {                                                                      \
    ASSERT(issame(rescale_to_unit(_type_{2.0, 49.9}), _type_{0.0, 1.0}));   \
    ASSERT(issame(rescale_to_unit(_type_{100.0, 49.9}), _type_{1.0, 0.0})); \
    ASSERT(issame(rescale_to_unit(_type_{1.0, 2.0, 3.0, 4.0, 5.0}),         \
                  _type_{0.0, 0.25, 0.5, 0.75, 1.0}));                      \
    ASSERT(issame(rescale_to_unit(_type_{2.0, 1.0, 5.0, 3.0, 4.0}),         \
                  _type_{0.25, 0.0, 1.0, 0.5, 0.75}));                      \
    ASSERT(issame(rescale_to_unit(_type_{12.0, 11.0, 15.0, 13.0, 14.0}),    \
                  _type_{0.25, 0.0, 1.0, 0.5, 0.75}));                      \
  } while (false)

int main() {
  TEST_ON_TYPE(std::vector<float>);
  TEST_ON_TYPE(std::vector<double>);
}


template <typename T>
T largest_divisor(T n) {
  for (T i = 2; i * i <= n; i++)
    if (n % i == 0) return n / i;
  return 1;
}

Replace these functions with a single generic function preserving the original behaviors.

template <std::integral T>
T largest_divisor(T n) {
  for (T i = 2; i * i <= n; i++)
    if (n % i == 0) return n / i;
  return 1;
}

Constrain the generic code using C++20 Concepts so that it only accepts integer types.

int main() { largest_divisor((float)3.5); }

template <typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
T largest_divisor(T n) {
  for (T i = 2; i * i <= n; i++)
    if (n % i == 0) return n / i;
  return 1;
}

Constrain the generic code using C++17 SFINAE so that it only accepts integer types.

int largest_divisor(int n) {
  for (int i = 2; i * i <= n; i++)
    if (n % i == 0) return n / i;
  return 1;
}
unsigned largest_divisor(unsigned n) {
  for (unsigned i = 2; i * i <= n; i++)
    if (n % i == 0) return n / i;
  return 1;
}
long largest_divisor(long n) {
  for (long i = 2; i * i <= n; i++)
    if (n % i == 0) return n / i;
  return 1;
}
unsigned short largest_divisor(unsigned short n) {
  for (unsigned short i = 2; i * i <= n; i++)
    if (n % i == 0) return n / i;
  return 1;
}

#define ASSERT(...)       \
  do {                    \
    if (!(__VA_ARGS__)) { \
      std::exit(-1);      \
    }                     \
  } while (false)

#define TEST_ON_TYPE(_type_)                            \
  do {                                                  \
    ASSERT(largest_divisor((_type_)3) == (_type_)1);    \
    ASSERT(largest_divisor((_type_)7) == (_type_)1);    \
    ASSERT(largest_divisor((_type_)10) == (_type_)5);   \
    ASSERT(largest_divisor((_type_)100) == (_type_)50); \
    ASSERT(largest_divisor((_type_)49) == (_type_)7);   \
  } while (false)

int main() {
  TEST_ON_TYPE(int);
  TEST_ON_TYPE(long);
  TEST_ON_TYPE(unsigned);
  TEST_ON_TYPE(unsigned short);
  TEST_ON_TYPE(unsigned long long);
}


template <typename T>
std::vector<T> factorize(T n) {
  std::vector<T> out = {};
  for (T i = 2; i * i <= n; i++) {
    if (n % i == 0) {
      n = n / i;
      out.push_back(i);
      i -= 1;
    }
  }
  out.push_back(n);
  return out;
}

template <std::integral T>
std::vector<T> factorize(T n) {
  std::vector<T> out = {};
  for (T i = 2; i * i <= n; i++) {
    if (n % i == 0) {
      n = n / i;
      out.push_back(i);
      i -= 1;
    }
  }
  out.push_back(n);
  return out;
}

template <typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
std::vector<T> factorize(T n) {
  std::vector<T> out = {};
  for (T i = 2; i * i <= n; i++) {
    if (n % i == 0) {
      n = n / i;
      out.push_back(i);
      i -= 1;
    }
  }
  out.push_back(n);
  return out;
}

std::vector<int> factorize(int n) {
  std::vector<int> out = {};
  for (int i = 2; i * i <= n; i++) {
    if (n % i == 0) {
      n = n / i;
      out.push_back(i);
      i -= 1;
    }
  }
  out.push_back(n);
  return out;
}
std::vector<unsigned> factorize(unsigned n) {
  std::vector<unsigned> out = {};
  for (unsigned i = 2; i * i <= n; i++) {
    if (n % i == 0) {
      n = n / i;
      out.push_back(i);
      i -= 1;
    }
  }
  out.push_back(n);
  return out;
}
std::vector<long> factorize(long n) {
  std::vector<long> out = {};
  for (long i = 2; i * i <= n; i++) {
    if (n % i == 0) {
      n = n / i;
      out.push_back(i);
      i -= 1;
    }
  }
  out.push_back(n);
  return out;
}

template <typename T>
bool issame(std::vector<T> a, std::vector<T> b) {
  if (a.size() != b.size()) return false;
  for (int i = 0; i < a.size(); i++) {
    if (a[i] != b[i]) return false;
  }
  return true;
}

#define ASSERT(...)       \
  do {                    \
    if (!(__VA_ARGS__)) { \
      std::exit(-1);      \
    }                     \
  } while (false)

#define TEST_ON_TYPE(_type_)                                                   \
  do {                                                                         \
    ASSERT(issame(factorize((_type_)2), std::vector<_type_>{2}));              \
    ASSERT(issame(factorize((_type_)4), std::vector<_type_>{2, 2}));           \
    ASSERT(issame(factorize((_type_)8), std::vector<_type_>{2, 2, 2}));        \
    ASSERT(issame(factorize((_type_)(3 * 19)), std::vector<_type_>{3, 19}));   \
    ASSERT(issame(factorize((_type_)(3 * 19 * 3 * 19)),                        \
                  std::vector<_type_>{3, 3, 19, 19}));                         \
    ASSERT(issame(factorize((_type_)(3 * 19 * 3 * 19 * 3 * 19)),               \
                  std::vector<_type_>{3, 3, 3, 19, 19, 19}));                  \
    ASSERT(issame(factorize((_type_)(3 * 19 * 19 * 19)),                       \
                  std::vector<_type_>{3, 19, 19, 19}));                        \
    ASSERT(                                                                    \
        issame(factorize((_type_)(3 * 2 * 3)), std::vector<_type_>{2, 3, 3})); \
  } while (false)

int main() {
  TEST_ON_TYPE(int);
  TEST_ON_TYPE(unsigned);
  TEST_ON_TYPE(long);
  TEST_ON_TYPE(unsigned long long);
}


template <typename T>
T remove_duplicates(T numbers) {
  T out = {};
  T has1 = {};
  T has2 = {};
  for (int i = 0; i < numbers.size(); i++) {
    if (std::find(has2.begin(), has2.end(), numbers[i]) != has2.end()) continue;
    if (std::find(has1.begin(), has1.end(), numbers[i]) != has1.end()) {
      has2.push_back(numbers[i]);
    } else {
      has1.push_back(numbers[i]);
    }
  }
  for (int i = 0; i < numbers.size(); i++) {
    if (std::find(has2.begin(), has2.end(), numbers[i]) == has2.end()) {
      out.push_back(numbers[i]);
    }
  }
  return out;
}

template <typename T>
  requires requires(const T &container, std::size_t idx, std::size_t oidx) {
    { container[idx] } -> std::same_as<typename T::const_reference>;
    { container[idx] == container[oidx] } -> std::convertible_to<bool>;
  }
T remove_duplicates(T numbers) {
  T out = {};
  T has1 = {};
  T has2 = {};
  for (int i = 0; i < numbers.size(); i++) {
    if (std::find(has2.begin(), has2.end(), numbers[i]) != has2.end()) continue;
    if (std::find(has1.begin(), has1.end(), numbers[i]) != has1.end()) {
      has2.push_back(numbers[i]);
    } else {
      has1.push_back(numbers[i]);
    }
  }
  for (int i = 0; i < numbers.size(); i++) {
    if (std::find(has2.begin(), has2.end(), numbers[i]) == has2.end()) {
      out.push_back(numbers[i]);
    }
  }
  return out;
}

Constrain the generic code using C++20 Concepts so that it only accepts sequenced containers with comparable elements.

template <
    typename T,
    std::enable_if_t<
        std::conjunction_v<
            std::is_same<typename T::const_reference,
                         decltype(std::declval<
                                  const T &>()[std::declval<std::size_t>()])>,
            std::is_convertible<decltype(std::declval<const T &>()
                                             [std::declval<std::size_t>()] ==
                                         std::declval<const T &>()
                                             [std::declval<std::size_t>()]),
                                bool>>,
        int> = 0>
T remove_duplicates(T numbers) {
  T out = {};
  T has1 = {};
  T has2 = {};
  for (int i = 0; i < numbers.size(); i++) {
    if (std::find(has2.begin(), has2.end(), numbers[i]) != has2.end()) continue;
    if (std::find(has1.begin(), has1.end(), numbers[i]) != has1.end()) {
      has2.push_back(numbers[i]);
    } else {
      has1.push_back(numbers[i]);
    }
  }
  for (int i = 0; i < numbers.size(); i++) {
    if (std::find(has2.begin(), has2.end(), numbers[i]) == has2.end()) {
      out.push_back(numbers[i]);
    }
  }
  return out;
}

Constrain the generic code using C++17 SFINAE so that it only accepts sequenced containers with comparable elements.

std::vector<int> remove_duplicates(std::vector<int> numbers) {
  std::vector<int> out = {};
  std::vector<int> has1 = {};
  std::vector<int> has2 = {};
  for (int i = 0; i < numbers.size(); i++) {
    if (std::find(has2.begin(), has2.end(), numbers[i]) != has2.end()) continue;
    if (std::find(has1.begin(), has1.end(), numbers[i]) != has1.end()) {
      has2.push_back(numbers[i]);
    } else {
      has1.push_back(numbers[i]);
    }
  }
  for (int i = 0; i < numbers.size(); i++) {
    if (std::find(has2.begin(), has2.end(), numbers[i]) == has2.end()) {
      out.push_back(numbers[i]);
    }
  }
  return out;
}
std::deque<std::string> remove_duplicates(std::deque<std::string> numbers) {
  std::deque<std::string> out = {};
  std::deque<std::string> has1 = {};
  std::deque<std::string> has2 = {};
  for (int i = 0; i < numbers.size(); i++) {
    if (std::find(has2.begin(), has2.end(), numbers[i]) != has2.end()) continue;
    if (std::find(has1.begin(), has1.end(), numbers[i]) != has1.end()) {
      has2.push_back(numbers[i]);
    } else {
      has1.push_back(numbers[i]);
    }
  }
  for (int i = 0; i < numbers.size(); i++) {
    if (std::find(has2.begin(), has2.end(), numbers[i]) == has2.end()) {
      out.push_back(numbers[i]);
    }
  }
  return out;
}

template <typename T>
bool issame(T a, T b) {
  if (a.size() != b.size()) return false;
  for (int i = 0; i < a.size(); i++) {
    if (a[i] != b[i]) return false;
  }
  return true;
}

#define ASSERT(...)       \
  do {                    \
    if (!(__VA_ARGS__)) { \
      std::exit(-1);      \
    }                     \
  } while (false)

int main() {
  ASSERT(issame(remove_duplicates(std::vector<int>{}), std::vector<int>{}));
  ASSERT(issame(remove_duplicates(std::vector<int>{1, 2, 3, 4}),
                std::vector<int>{1, 2, 3, 4}));
  ASSERT(issame(remove_duplicates(std::vector<int>{1, 2, 3, 2, 4, 3, 5}),
                std::vector<int>{1, 4, 5}));

  ASSERT(issame(remove_duplicates(std::vector<char>{}), std::vector<char>{}));
  ASSERT(issame(remove_duplicates(std::vector<char>{1, 2, 3, 4}),
                std::vector<char>{1, 2, 3, 4}));
  ASSERT(issame(remove_duplicates(std::vector<char>{1, 2, 3, 2, 4, 3, 5}),
                std::vector<char>{1, 4, 5}));

  ASSERT(issame(remove_duplicates(std::deque<std::string>{}),
                std::deque<std::string>{}));
  ASSERT(issame(remove_duplicates(std::deque<std::string>{"1", "2", "3", "4"}),
                std::deque<std::string>{"1", "2", "3", "4"}));
  ASSERT(issame(remove_duplicates(
                    std::deque<std::string>{"1", "2", "3", "2", "4", "3", "5"}),
                std::deque<std::string>{"1", "4", "5"}));
}