Блог пользователя ivan100sic

Автор ivan100sic, история, 3 года назад, По-английски

Take a look at this snippet:

#include <iostream>
#include <string>
using namespace std;

template<const char* tag>
struct html_element {
  string s;

  template<typename... Args>
  html_element(Args... args) : s((... + (string)args)) {}

  operator string() { return string("<") + tag + ">" + s + "</" + tag + ">"; }
};

const char html_c[] = "html";
const char body_c[] = "body";
const char h2_c[] = "h2";

using html = html_element<html_c>;
using body = html_element<body_c>;
using h2 = html_element<h2_c>;

int main() {
  string doc{
    html{
      body{
        h2{ "hello" },
        h2{ "world" }
      }
    }
  };

  cout << doc << '\n';
}

Thank you for your attention

  • Проголосовать: нравится
  • +204
  • Проголосовать: не нравится

»
3 года назад, # |
  Проголосовать: нравится -36 Проголосовать: не нравится

That definitely looks like Reactjs or something similar to me

»
3 года назад, # |
  Проголосовать: нравится +27 Проголосовать: не нравится

May I direct your attention to https://github.com/csb6/html-plus-plus

»
3 года назад, # |
Rev. 2   Проголосовать: нравится +5 Проголосовать: не нравится

What will happen in this code if you want to use "img" in html?

»
3 года назад, # |
  Проголосовать: нравится +6 Проголосовать: не нравится

is this some kind of peasant joke im not able to understand

»
3 года назад, # |
Rev. 2   Проголосовать: нравится -13 Проголосовать: не нравится

There is also the crow framework for proper web development in C++. LinkedIn has a good course for it.

»
3 года назад, # |
  Проголосовать: нравится +10 Проголосовать: не нравится

Unpopular opinion: C++ is both the best and the worst language, for any purpose.

Okay, this does like awesome at first but then you find out you miss a couple of things that make this code terribly inefficient. For example:

template<typename... Args> html_element(Args... args) : s((... + (string)args)) {}

This invokes copy constructor of args which may be inefficient. Or maybe not, if copy elision takes place. Either way you probably don't want to hope it works as you expect it to, so you should probably add a universal reference. Also this is going to break if args is empty, and I wouldn't recommend C-style cast, and you should perfect-forward arguments, something like this:

template<typename... Args> html_element(Args&&... args) : s((""s + ... + std::forward<Args>(args))) {}

Then, you most likely want to construct HTML in-place and not copy it here and there, so you may think it's a good idea to make std::string take this via an rvalue reference:

operator string() && { return string("<") + tag + ">" + std::move(s) + "</" + tag + ">"; }

This code may look fine but it still involves copying because a big string is still constructed every time via concatenation. You may think a std::string_stream would work well:

template<typename Stream, const char* tag> Stream& operator<<(Stream& ss, const html_element<tag>& element) { return ss << "<" << tag << ">" << element.s << "</" << tag << ">"; }

But you'd still have std::string s member which would ruin performance. Honestly I have no idea how to fix this except resorting to slow-compilation compile-time template-based strings. Or just using a template compiler instead, which you should be using anyway.


Disclaimer: I haven't tried to compile any of these codes.