base_canonical_solution:
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;
}

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

concepts_canonical_solution:
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;
}

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

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

sfinae_canonical_solution:
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;
}

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

starter_code:
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;
}

tests:
#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>);
}


base_canonical_solution:
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;
}

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

concepts_canonical_solution:
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.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;
}

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

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

sfinae_canonical_solution:
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.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;
}

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

starter_code:
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;
}

tests:
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);
}