Вариативный класс шаблона, содержащий массив другого класса шаблона

Я создаю свою собственную СУБД для практики C++. Я придумал решение, в котором каждый столбец может иметь тип и является шаблоном. Вот так выглядит строка, но она не работает

template <typename... col_types>
struct row {
  row(std::tuple<std::function<bool(col_types)>, bool, col_types>...col_data){
    int i = 0;
    ([&]{
        columns[i] = std::make_unique<column_impl<decltype(std::get<2>(col_data))>>(std::get<0>(col_data), std::get<1>(col_data), std::get<2>(col_data));
        i++;
    }(), ...);
  }
  std::array<std::unique_ptr<column_impl<col_types>>, sizeof...(col_types)> columns;
};

А вот column_impl

template <typename data_t>
struct column_impl {
  column_impl<data_t>() {}
  column_impl<data_t>(std::function<bool(data_t)> _constraint) : constraint(_constraint) {}
  column_impl<data_t>(std::function<bool(data_t)> _constraint, bool _is_nullable)
      : constraint(_constraint), is_nullable(_is_nullable) {}

  // This constructor requires to validate whether provided data
  // satisfies provided constraint. If constraint isn't satisfied
  // an exception gets thrown. It needs to be handled
  column_impl<data_t>(std::function<bool(data_t)> _constraint, bool _is_nullable, data_t _value)
      : constraint(_constraint), is_nullable(_is_nullable) {
    if (validate_data()) {
      value = _value;
    } else {
      throw std::invalid_argument("Provived data couldn't satisfy column's constraint");
    }
  }

  std::function<bool(data_t)> constraint = [](data_t) { return true; };
  bool is_nullable = false;
  data_t value;
  auto get_column_type_variant() { return std::variant<data_t>(); }

  bool validate_data() { return constraint(value); }

  template <typename T>
  bool validate_type(T) {
    return std::is_nothrow_convertible<T, data_t>();
  }
};

Любые идеи, как создать контейнер для столбцов внутри строки и создать конструктор, который распаковывает кортежи в строку? Я не могу заставить его работать. Я знаю, что этот массив не должен работать, но я понятия не имею, как его лучше написать. А еще я не хочу вектор. Я мог бы написать полиморфную оболочку вроде
struct column{some_type_containing_column_impls column_obj;}, но я понятия не имею, как это сделать. И как правильно распаковать эти кортежи в объект column_impl?

Мне кажется, вы пытаетесь создать std::array, где каждое значение относится к другому типу? К сожалению, C++ так не работает. Вам нужно будет найти какой-то другой подход. Возможно, подход на основе std::tuple.

Sam Varshavchik 18.02.2023 14:08

Да, как я уже сказал, это не правильный подход. Но я не могу думать ни о чем другом, и мне нужна помощь.

k1t3k 18.02.2023 14:09

Как я уже сказал, подход на основе кортежей должен работать. Но это будет работать совершенно по-другому.

Sam Varshavchik 18.02.2023 16:06
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
59
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Использование только аргументов шаблона, не являющихся типом, может сделать это.

template<class T>
bool default_constraint(T) {
    return true;
}

template<class T, bool nullable = true, bool(constraint)(T) = default_constraint>
class column {
    T data;
    bool is_null;
public:
    column() : data(), is_null(true) { ///< T must be DefaultConstructable
        if (!validate())
            throw std::invalid_argument("Provided data couldn't satisfy column's constraint");
    }

    column(T data) : data(data), is_null(false) {
        if (!validate())
            throw std::invalid_argument("Provided data couldn't satisfy column's constraint");
    }

    bool validate() {
        return nullable || is_null || constraint(data);
    }

    T get() {
        return data;
    }
};

template<class... C>
struct row {
    std::tuple<C...> columns;

    row(C&&... c) : columns(std::forward<C>(c)...) {}

    template<int index>
    auto get() {
        return std::get<index>(columns).get();
    }
};

bool require_positive(int i) {
    return i >= 0;
}

int main() {
    typedef row<column<int>, column<float>, column<bool>> MyRow;
    MyRow r{1, 2.3f, true};

    using MyRow2 = row<column<int, false, require_positive>, column<float>>;
    MyRow2 r2{-1, 2.5}; ///< exception thrown
}

Я знаю, может быть, вам нужна только «идея» того, как реализовать, но я просто публикую код здесь для ясности.

Другие вопросы по теме