包含另一个模板类数组的可变参数模板类

huangapple go评论127阅读模式
英文:

Variadic template class containing array of another template class

问题

I'm creating my own RDBMS to practice C++. I came up with a solution where each column can have a type and is a template. This is what a row looks like, but it doesn't work

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

And here is a 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>();
  }
};

Any ideas how to create a container for columns inside of a row and create a constructor that unpacks tuples into a row? I can't get it working. I know this array is not supposed to work, but I have no idea how to write it better. And also I don't want a vector. I could write a polymorphic wrapper like

struct column{some_type_containing_column_impls column_obj;}

but I have no idea how to do it.
And how to properly unpack those tuples into column_impl objects?

英文:

I'm creating my own RDBMS to practice C++. I came up with a solution where each column can have a type and is a template. This is what a row looks like, but it doesn't work

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

And here is a column_impl

template &lt;typename data_t&gt;
struct column_impl {
  column_impl&lt;data_t&gt;() {}
  column_impl&lt;data_t&gt;(std::function&lt;bool(data_t)&gt; _constraint) : constraint(_constraint) {}
  column_impl&lt;data_t&gt;(std::function&lt;bool(data_t)&gt; _constraint, bool _is_nullable)
      : constraint(_constraint), is_nullable(_is_nullable) {}

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

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

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

  template &lt;typename T&gt;
  bool validate_type(T) {
    return std::is_nothrow_convertible&lt;T, data_t&gt;();
  }
};

Any ideas how to create a container for columns inside of a row and create a constructor that unpacks tuples into a row? I can't get it working. I know this array is not supposed to work, but I have no idea how to write it better. And also I don't want a vector. I could write a polymorphic wrapper like<br/>
struct column{some_type_containing_column_impls column_obj;},
but I have no idea how to do it.
And how to properly unpack those tuples into column_impl obj?

答案1

得分: 0

以下是翻译好的部分,其中代码部分没有被翻译:

"Using only non-type template arguments can do the thing."

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
}

希望这有所帮助。如果您需要进一步的解释或翻译,请告诉我。

英文:

Using only non-type template arguments can do the thing.

template&lt;class T&gt;
bool default_constraint(T) {
    return true;
}

template&lt;class T, bool nullable = true, bool(constraint)(T) = default_constraint&gt;
class column {
    T data;
    bool is_null;
public:
    column() : data(), is_null(true) { ///&lt; T must be DefaultConstructable
        if (!validate())
	        throw std::invalid_argument(&quot;Provided data couldn&#39;t satisfy column&#39;s constraint&quot;);
    }

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

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

    T get() {
	    return data;
    }
};

template&lt;class... C&gt;
struct row {
    std::tuple&lt;C...&gt; columns;

    row(C&amp;&amp;... c) : columns(std::forward&lt;C&gt;(c)...) {}

    template&lt;int index&gt;
    auto get() {
	    return std::get&lt;index&gt;(columns).get();
    }
};

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

int main() {
    typedef row&lt;column&lt;int&gt;, column&lt;float&gt;, column&lt;bool&gt;&gt; MyRow;
    MyRow r{1, 2.3f, true};

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

I know maybe you only want the "idea" of how to implement, but I just post the code here for clarity.

huangapple
  • 本文由 发表于 2023年2月18日 21:01:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/75493509.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定