<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[compiletime string validator generator]]></title><description><![CDATA[<p>Hab nicht viel zu dem Thema im Internet gefunden, also poste ich es mal, vielleicht interessiert es wen.<br />
Compiled ohne Fehler mit gcc 4.6.</p>
<p>Das Prinzip ist eigentlich sehr simpel, wenn man es verstanden hat. Jedem Operator aus der EBNF wird ein Typ aus c++ zugeordnet. So wird <code>A = B | C;</code> zu <code>typedef alt&lt; B , C &gt; A;</code> .<br />
Wenn man Rekursion verwenden will, kann man das so machen: <code>A = B , [ A ]</code> =&gt; <code>struct A : concat&lt; B , opt&lt; A &gt; &gt; {};</code> .<br />
Terminale werden so definiert: &quot;ABC&quot; =&gt; <code>terminal&lt; 'A' , 'B' , 'C' &gt;</code></p>
<p>Für den parsing Prozess ist die Funktion</p>
<pre><code class="language-cpp">template&lt; unsigned int N &gt;
constexpr static unsigned int parse( const char (&amp;arr) , unsigned int i );
</code></pre>
<p>zuständig, die in jeder Symbolsklasse definiert wird. Übergeben wird ihr der String in arr und die derzeitige parse-Position im array in i. Die Rückgabe ist entweder das unsigned int maximum, wenn das Symbol nicht erstellt werden konnte, oder eine neue Position im String, wenn das Symbol erstellt werden konnte.</p>
<pre><code class="language-cpp">const unsigned int uimax = 0u - 1;

template&lt; char ... &gt;
struct terminal;
template&lt; char Last &gt;
struct terminal&lt; Last &gt;
{
    template&lt; unsigned int N &gt;
    static constexpr unsigned int parse( const char (&amp;arr)[N] , unsigned int i )
    {
        return
        i &lt; N ?
            arr[i] == Last ?
                i + 1 :
                uimax
            : uimax;
    }
};
template&lt; char First , char ...Tail &gt;
struct terminal&lt; First , Tail... &gt;
{
    template&lt; unsigned int N &gt;
    static constexpr unsigned int parse( const char (&amp;arr)[N] , unsigned int i )
    {
        return
        i &lt; N ?
            arr[i] == First ?
                terminal&lt; Tail... &gt;::parse( arr , i + 1 ) :
                uimax :
            uimax;
    }
};
template&lt; class ... &gt;
struct concat;
template&lt;&gt;
struct concat&lt;&gt;
{
    template&lt; unsigned int N &gt;
    static constexpr unsigned int parse( const char (&amp;arr)[N] , unsigned int i )
    {
        return i;
    }
};
template&lt; class Head , class ...Tail &gt;
struct concat&lt; Head , Tail... &gt;
{
    template&lt; unsigned int N &gt;
    static constexpr unsigned int parse( const char (&amp;arr)[N] , unsigned int i )
    {
        return
        Head::parse( arr , i ) == uimax ?
            uimax :
            concat&lt; Tail... &gt;::parse( arr , Head::parse( arr , i ) );
    }
};
template&lt; class ... &gt;
struct alt;
template&lt; class Last &gt;
struct alt&lt; Last &gt;
{
    template&lt; unsigned int N &gt;
    static constexpr unsigned int parse( const char (&amp;arr)[N] , unsigned int i )
    {
        return
        Last::parse( arr , i ) == uimax ?
            uimax :
            Last::parse( arr , i );
    }
};
template&lt; class Head , class ...Tail &gt;
struct alt&lt; Head , Tail... &gt;
{
    template&lt; unsigned int N &gt;
    static constexpr unsigned int parse( const char (&amp;arr)[N] , unsigned int i )
    {
        return
        Head::parse( arr , i ) == uimax ?
            alt&lt; Tail... &gt;::parse( arr , i ) :
            Head::parse( arr , i );
    }
};
template&lt; class Symbol &gt;
struct opt
{
    template&lt; unsigned int N &gt;
    static constexpr unsigned int parse( const char (&amp;arr)[N] , unsigned int i )
    {
        return
        Symbol::parse( arr , i ) == uimax ?
            i :
            Symbol::parse( arr , i );
    }
};
template&lt; class Symbol &gt;
struct repet
{
    template&lt; unsigned int N &gt;
    static constexpr unsigned int parse( const char (&amp;arr)[N] , unsigned int i )
    {
        return
        Symbol::parse( arr , i ) == uimax ?
            i :
            repet&lt; Symbol &gt;::parse( arr , Symbol::parse( arr , i ) );
    }
};

//Anwendung: parentheses matching
typedef repet
&lt;
    alt
    &lt;
        terminal&lt; ' ' &gt; ,
        terminal&lt; '\n' &gt;
    &gt;
&gt; white;

struct parentheses
    : concat
    &lt;
        white ,
        terminal&lt; '(' &gt; ,
        white ,
        opt&lt; parentheses &gt; ,
        terminal&lt; ')' &gt; ,
        white ,
        opt&lt; parentheses &gt;
    &gt;
{
};

int main()
{
    constexpr char str_valid[] = &quot;()()( () \n () ( ( ) ) )&quot;;
    constexpr char str_invalid[] = &quot;()( ( ( ( ) ) () ) (&quot;;
    static_assert( parentheses::parse( str_valid , 0 ) == sizeof( str_valid ) - 1 , &quot;&quot; );
    static_assert( parentheses::parse( str_invalid , 0 ) != sizeof( str_invalid ) - 1 , &quot;&quot; );
}
</code></pre>
<p>Im Moment seh ich noch keinen wirklichen Anwendungszweck, erhoffe mir aber, dass man vielleicht Objekte mit constexpr Konstruktor zurückgeben kann um einen AST aufzubauen.<br />
Das System, dass man jedes Symbol einfach die parse - Funktion &quot;überschreiben&quot; lässt, kann man übrigens auch hervorragend für einen runtime - Parser (bzw. einen Parser Generator zur compiletime) verwenden.<br />
Kompletter source wäre zu lang, aber so könnte das dann aussehen:</p>
<pre><code class="language-cpp">template&lt; class Symbol &gt;
class repet
    : public std::vector&lt; Symbol &gt;
{
public:
    template&lt; class IteratorType &gt;
    bool parse( IteratorType &amp;begin , IteratorType end )
    //Diese Funktion wird von jedem Symbol definiert. Sie soll true ergeben, wenn das Symbol erstellt werden konnte und begin erhöhen, falls nötig.
    {
        vec_type::push_back( Symbol() );
        while( vec_type::back().parse( begin , end ) )
        {
            vec_type.push_back( Symbol() );
        }
        vec_type::pop_back();
        return true;
    }
private:
    typedef std::vector&lt; Symbol &gt; vec_type;
};
</code></pre>
<p>So kann man dann sehr leicht einen AST erstellen (leider nur zur runtime).</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/297705/compiletime-string-validator-generator</link><generator>RSS for Node</generator><lastBuildDate>Fri, 14 Aug 2026 06:45:14 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/297705.rss" rel="self" type="application/rss+xml"/><pubDate>Thu, 05 Jan 2012 08:34:43 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to compiletime string validator generator on Thu, 05 Jan 2012 17:24:01 GMT]]></title><description><![CDATA[<p>Hab nicht viel zu dem Thema im Internet gefunden, also poste ich es mal, vielleicht interessiert es wen.<br />
Compiled ohne Fehler mit gcc 4.6.</p>
<p>Das Prinzip ist eigentlich sehr simpel, wenn man es verstanden hat. Jedem Operator aus der EBNF wird ein Typ aus c++ zugeordnet. So wird <code>A = B | C;</code> zu <code>typedef alt&lt; B , C &gt; A;</code> .<br />
Wenn man Rekursion verwenden will, kann man das so machen: <code>A = B , [ A ]</code> =&gt; <code>struct A : concat&lt; B , opt&lt; A &gt; &gt; {};</code> .<br />
Terminale werden so definiert: &quot;ABC&quot; =&gt; <code>terminal&lt; 'A' , 'B' , 'C' &gt;</code></p>
<p>Für den parsing Prozess ist die Funktion</p>
<pre><code class="language-cpp">template&lt; unsigned int N &gt;
constexpr static unsigned int parse( const char (&amp;arr) , unsigned int i );
</code></pre>
<p>zuständig, die in jeder Symbolsklasse definiert wird. Übergeben wird ihr der String in arr und die derzeitige parse-Position im array in i. Die Rückgabe ist entweder das unsigned int maximum, wenn das Symbol nicht erstellt werden konnte, oder eine neue Position im String, wenn das Symbol erstellt werden konnte.</p>
<pre><code class="language-cpp">const unsigned int uimax = 0u - 1;

template&lt; char ... &gt;
struct terminal;
template&lt; char Last &gt;
struct terminal&lt; Last &gt;
{
    template&lt; unsigned int N &gt;
    static constexpr unsigned int parse( const char (&amp;arr)[N] , unsigned int i )
    {
        return
        i &lt; N ?
            arr[i] == Last ?
                i + 1 :
                uimax
            : uimax;
    }
};
template&lt; char First , char ...Tail &gt;
struct terminal&lt; First , Tail... &gt;
{
    template&lt; unsigned int N &gt;
    static constexpr unsigned int parse( const char (&amp;arr)[N] , unsigned int i )
    {
        return
        i &lt; N ?
            arr[i] == First ?
                terminal&lt; Tail... &gt;::parse( arr , i + 1 ) :
                uimax :
            uimax;
    }
};
template&lt; class ... &gt;
struct concat;
template&lt;&gt;
struct concat&lt;&gt;
{
    template&lt; unsigned int N &gt;
    static constexpr unsigned int parse( const char (&amp;arr)[N] , unsigned int i )
    {
        return i;
    }
};
template&lt; class Head , class ...Tail &gt;
struct concat&lt; Head , Tail... &gt;
{
    template&lt; unsigned int N &gt;
    static constexpr unsigned int parse( const char (&amp;arr)[N] , unsigned int i )
    {
        return
        Head::parse( arr , i ) == uimax ?
            uimax :
            concat&lt; Tail... &gt;::parse( arr , Head::parse( arr , i ) );
    }
};
template&lt; class ... &gt;
struct alt;
template&lt; class Last &gt;
struct alt&lt; Last &gt;
{
    template&lt; unsigned int N &gt;
    static constexpr unsigned int parse( const char (&amp;arr)[N] , unsigned int i )
    {
        return
        Last::parse( arr , i ) == uimax ?
            uimax :
            Last::parse( arr , i );
    }
};
template&lt; class Head , class ...Tail &gt;
struct alt&lt; Head , Tail... &gt;
{
    template&lt; unsigned int N &gt;
    static constexpr unsigned int parse( const char (&amp;arr)[N] , unsigned int i )
    {
        return
        Head::parse( arr , i ) == uimax ?
            alt&lt; Tail... &gt;::parse( arr , i ) :
            Head::parse( arr , i );
    }
};
template&lt; class Symbol &gt;
struct opt
{
    template&lt; unsigned int N &gt;
    static constexpr unsigned int parse( const char (&amp;arr)[N] , unsigned int i )
    {
        return
        Symbol::parse( arr , i ) == uimax ?
            i :
            Symbol::parse( arr , i );
    }
};
template&lt; class Symbol &gt;
struct repet
{
    template&lt; unsigned int N &gt;
    static constexpr unsigned int parse( const char (&amp;arr)[N] , unsigned int i )
    {
        return
        Symbol::parse( arr , i ) == uimax ?
            i :
            repet&lt; Symbol &gt;::parse( arr , Symbol::parse( arr , i ) );
    }
};

//Anwendung: parentheses matching
typedef repet
&lt;
    alt
    &lt;
        terminal&lt; ' ' &gt; ,
        terminal&lt; '\n' &gt;
    &gt;
&gt; white;

struct parentheses
    : concat
    &lt;
        white ,
        terminal&lt; '(' &gt; ,
        white ,
        opt&lt; parentheses &gt; ,
        terminal&lt; ')' &gt; ,
        white ,
        opt&lt; parentheses &gt;
    &gt;
{
};

int main()
{
    constexpr char str_valid[] = &quot;()()( () \n () ( ( ) ) )&quot;;
    constexpr char str_invalid[] = &quot;()( ( ( ( ) ) () ) (&quot;;
    static_assert( parentheses::parse( str_valid , 0 ) == sizeof( str_valid ) - 1 , &quot;&quot; );
    static_assert( parentheses::parse( str_invalid , 0 ) != sizeof( str_invalid ) - 1 , &quot;&quot; );
}
</code></pre>
<p>Im Moment seh ich noch keinen wirklichen Anwendungszweck, erhoffe mir aber, dass man vielleicht Objekte mit constexpr Konstruktor zurückgeben kann um einen AST aufzubauen.<br />
Das System, dass man jedes Symbol einfach die parse - Funktion &quot;überschreiben&quot; lässt, kann man übrigens auch hervorragend für einen runtime - Parser (bzw. einen Parser Generator zur compiletime) verwenden.<br />
Kompletter source wäre zu lang, aber so könnte das dann aussehen:</p>
<pre><code class="language-cpp">template&lt; class Symbol &gt;
class repet
    : public std::vector&lt; Symbol &gt;
{
public:
    template&lt; class IteratorType &gt;
    bool parse( IteratorType &amp;begin , IteratorType end )
    //Diese Funktion wird von jedem Symbol definiert. Sie soll true ergeben, wenn das Symbol erstellt werden konnte und begin erhöhen, falls nötig.
    {
        vec_type::push_back( Symbol() );
        while( vec_type::back().parse( begin , end ) )
        {
            vec_type.push_back( Symbol() );
        }
        vec_type::pop_back();
        return true;
    }
private:
    typedef std::vector&lt; Symbol &gt; vec_type;
};
</code></pre>
<p>So kann man dann sehr leicht einen AST erstellen (leider nur zur runtime).</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2163930</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2163930</guid><dc:creator><![CDATA[GorbGorb]]></dc:creator><pubDate>Thu, 05 Jan 2012 17:24:01 GMT</pubDate></item><item><title><![CDATA[Reply to compiletime string validator generator on Thu, 05 Jan 2012 10:02:44 GMT]]></title><description><![CDATA[<p>Cool, danke! <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f44d.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--thumbs_up"
      title=":+1:"
      alt="👍"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/2163968</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2163968</guid><dc:creator><![CDATA[Liver]]></dc:creator><pubDate>Thu, 05 Jan 2012 10:02:44 GMT</pubDate></item><item><title><![CDATA[Reply to compiletime string validator generator on Thu, 05 Jan 2012 10:07:34 GMT]]></title><description><![CDATA[<p>Vielleicht kannst du etwas mehr dazu schreiben, bspw. welches Problem geloest werden soll, wie der Ansatz ist, ... und ein paar erklaerende Worte.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2163971</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2163971</guid><dc:creator><![CDATA[knivil]]></dc:creator><pubDate>Thu, 05 Jan 2012 10:07:34 GMT</pubDate></item><item><title><![CDATA[Reply to compiletime string validator generator on Thu, 05 Jan 2012 12:13:57 GMT]]></title><description><![CDATA[<p>knivil schrieb:</p>
<blockquote>
<p>Vielleicht kannst du etwas mehr dazu schreiben, bspw. welches Problem geloest werden soll, wie der Ansatz ist, ... und ein paar erklaerende Worte.</p>
</blockquote>
<p>Mach ich jetzt... es war nur so dass die Sonne schon wieder aufging <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f642.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--slightly_smiling_face"
      title="=)"
      alt="🙂"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/2164045</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2164045</guid><dc:creator><![CDATA[GorbGorb]]></dc:creator><pubDate>Thu, 05 Jan 2012 12:13:57 GMT</pubDate></item><item><title><![CDATA[Reply to compiletime string validator generator on Sat, 07 Jan 2012 14:07:38 GMT]]></title><description><![CDATA[<p>So, ich jetzt konnte ich auch einen AST generieren und damit einen kleinen Rechner bauen. Er kann im Moment nur + und * und nimmt auch &quot;05&quot; als Zahl an, aber es geht hier ja nur darum, das ganze zu demonstrieren. Auszug aus main.cpp:</p>
<pre><code class="language-cpp">#include &quot;operators.hpp&quot;

#include &lt;string&gt;
#include &lt;iostream&gt;

DEF_TERMINAL( MyTerminal , &quot;asdfasdf&quot; )

int main()
{
    //compile time parsing
    constexpr const_string&lt; char &gt; cstr = &quot;2  + 54 * 2 + 83&quot;;
    constexpr addition a( cstr );
    static_assert( a.eval() == 193 , &quot;&quot;);
    constexpr const_string&lt; char &gt; cstr2 = &quot;asd fasdf&quot;;
    constexpr MyTerminal t( cstr2 );
    static_assert( !t.valid() , &quot;&quot; );

    //run time parsing, but I guess this is very inefficient
    std::string str;
    std::cin &gt;&gt; str;
    const_string&lt; char &gt; cstr3( &amp;*str.begin() , &amp;*str.end() );
    addition a_run_time( cstr3 );
    if( a_run_time.end() == str.size() )
        std::cout &lt;&lt; a_run_time.eval() &lt;&lt; std::endl;
    else
        std::cout &lt;&lt; &quot;parse error&quot; &lt;&lt; std::endl;
}
</code></pre>
<p>Den kompletten source kann man sich hier runterladen:<br />
<a href="http://www.file-upload.net/download-4010616/compile-time-parser.zip.html" rel="nofollow">http://www.file-upload.net/download-4010616/compile-time-parser.zip.html</a></p>
<p>Das hat jetzt vielleicht so langsam einen Sinn... vielleicht wird man irgendwann z.B. SQL in c++ compilen können (inklusive Syntaxchecks und c++ performance).</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2164864</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2164864</guid><dc:creator><![CDATA[GorbGorb]]></dc:creator><pubDate>Sat, 07 Jan 2012 14:07:38 GMT</pubDate></item><item><title><![CDATA[Reply to compiletime string validator generator on Sat, 07 Jan 2012 20:05:03 GMT]]></title><description><![CDATA[<p>Find ich persönlich richtig genial.</p>
<pre><code class="language-cpp">Das hat jetzt vielleicht so langsam einen Sinn... vielleicht wird man irgendwann z.B. SQL in c++ compilen können (inklusive Syntaxchecks und c++ performance).
</code></pre>
<p>Wäre es denn theoretisch möglich? Wenn ja, lust eine minimale Scriptsprache mit einem &quot;print xyz&quot; Befehl zu bauen? Würde das gerne sehen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2164990</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2164990</guid><dc:creator><![CDATA[Ethon]]></dc:creator><pubDate>Sat, 07 Jan 2012 20:05:03 GMT</pubDate></item><item><title><![CDATA[Reply to compiletime string validator generator on Sat, 07 Jan 2012 20:23:49 GMT]]></title><description><![CDATA[<p>Ethon schrieb:</p>
<blockquote>
<p>Find ich persönlich richtig genial.</p>
<pre><code class="language-cpp">Das hat jetzt vielleicht so langsam einen Sinn... vielleicht wird man irgendwann z.B. SQL in c++ compilen können (inklusive Syntaxchecks und c++ performance).
</code></pre>
<p>Wäre es denn theoretisch möglich? Wenn ja, lust eine minimale Scriptsprache mit einem &quot;print xyz&quot; Befehl zu bauen? Würde das gerne sehen.</p>
</blockquote>
<p>Oder ein &quot;in c++ c++ compiler xD&quot; Lol könnte der sich dann nicht selbst kompiliern? oO Kann mir das gerade nicht so richtig vorstellen ... ein Compiler der sich während des Erstellens selbst compiled?!</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2164998</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2164998</guid><dc:creator><![CDATA[pyhax]]></dc:creator><pubDate>Sat, 07 Jan 2012 20:23:49 GMT</pubDate></item><item><title><![CDATA[Reply to compiletime string validator generator on Sat, 07 Jan 2012 21:02:37 GMT]]></title><description><![CDATA[<p>Ethon schrieb:</p>
<blockquote>
<p>Find ich persönlich richtig genial.</p>
<pre><code class="language-cpp">Das hat jetzt vielleicht so langsam einen Sinn... vielleicht wird man irgendwann z.B. SQL in c++ compilen können (inklusive Syntaxchecks und c++ performance).
</code></pre>
<p>Wäre es denn theoretisch möglich?</p>
</blockquote>
<p>Ich wüsste nicht, warum es nicht möglich sein sollte. Den query könnte man natürlich nicht zur Compilezeit ausführen (macht ja auch wenig Sinn), aber man kann schonmal den Befehl in c++ (und dann in Maschinencode) übersetzen.</p>
<blockquote>
<p>Wenn ja, lust eine minimale Scriptsprache mit einem &quot;print xyz&quot; Befehl zu bauen? Würde das gerne sehen.</p>
</blockquote>
<p>Wie meinst du das? Eine Sprache die nur &quot;print string&quot; kann, beim compilen übersetzt wird und den string dann über ein <code>code.exec()</code> zur Laufzeit ausgibt? Es gäbe vielleicht die Möglichkeit, über ein static_assert eine Ausgabe beim compilen zu erzeugen... aber ich wüsste jetzt so spontan nicht, wie ich einen <code>constexpr char substr[]</code> aus einem anderen constexpr string generieren könnte...</p>
<p>pyhax schrieb:</p>
<blockquote>
<p>Oder ein &quot;in c++ c++ compiler xD&quot; Lol könnte der sich dann nicht selbst kompiliern? oO Kann mir das gerade nicht so richtig vorstellen ... ein Compiler der sich während des Erstellens selbst compiled?!</p>
</blockquote>
<p>Er könnte seinen eigenen Quellcode übersetzen, ja. Aber so ungewöhnlich ist das nicht, der gcc oder javac können das auch.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2165002</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2165002</guid><dc:creator><![CDATA[GorbGorb]]></dc:creator><pubDate>Sat, 07 Jan 2012 21:02:37 GMT</pubDate></item><item><title><![CDATA[Reply to compiletime string validator generator on Sat, 07 Jan 2012 21:46:48 GMT]]></title><description><![CDATA[<p>GorbGorb schrieb:</p>
<blockquote>
<p>Es gäbe vielleicht die Möglichkeit, über ein static_assert eine Ausgabe beim compilen zu erzeugen... aber ich wüsste jetzt so spontan nicht, wie ich einen <code>constexpr char substr[]</code> aus einem anderen constexpr string generieren könnte...</p>
</blockquote>
<p>Eine Möglichkeit:</p>
<pre><code class="language-cpp">#include &lt;cstddef&gt;
#include &lt;iostream&gt;

template &lt;typename T&gt; struct identity
{
    using type = T;
};
template &lt;std::ptrdiff_t... i&gt; struct index_list
    : identity&lt;index_list&lt;i...&gt;&gt; {};

template &lt;typename... T&gt; struct concat_index_lists
    : concat_index_lists&lt;typename T::type...&gt; {};
template &lt;std::ptrdiff_t... i, std::ptrdiff_t... j, typename... T&gt; struct concat_index_lists&lt;index_list&lt;i...&gt;, index_list&lt;j...&gt;, T...&gt;
    : concat_index_lists&lt;index_list&lt;i..., j...&gt;, T...&gt; {};
template &lt;std::ptrdiff_t... i&gt; struct concat_index_lists&lt;index_list&lt;i...&gt;&gt;
    : identity&lt;index_list&lt;i...&gt;&gt; {};

template &lt;typename T, std::ptrdiff_t shift&gt; struct shift_index_list
    : shift_index_list&lt;typename T::type, shift&gt; {};
template &lt;std::ptrdiff_t... i, std::ptrdiff_t shift&gt; struct shift_index_list&lt;index_list&lt;i...&gt;, shift&gt;
    : identity&lt;index_list&lt;(i + shift)...&gt;&gt; {};

template &lt;std::size_t N&gt; struct make_index_list
    : concat_index_lists&lt;make_index_list&lt;N / 2&gt;, shift_index_list&lt;make_index_list&lt;N / 2&gt;, N / 2&gt;, shift_index_list&lt;make_index_list&lt;N % 2&gt;, N - 1&gt;&gt; {};
template &lt;&gt; struct make_index_list&lt;1&gt;
    : identity&lt;index_list&lt;0&gt;&gt; {};
template &lt;&gt; struct make_index_list&lt;0&gt;
    : identity&lt;index_list&lt;&gt;&gt; {};

template &lt;const char* str, std::ptrdiff_t begin, std::ptrdiff_t end, typename = typename make_index_list&lt;end - begin&gt;::type&gt; struct substr;
template &lt;const char* str, std::ptrdiff_t begin, std::ptrdiff_t end, std::ptrdiff_t... i&gt; struct substr&lt;str, begin, end, index_list&lt;i...&gt;&gt;
{
    static constexpr char value[] = { str[ i + begin ]..., '\0' };
};
template &lt;const char* str, std::ptrdiff_t begin, std::ptrdiff_t end, std::ptrdiff_t... i&gt;
constexpr char substr&lt;str, begin, end, index_list&lt;i...&gt;&gt;::value[];

extern constexpr char test[] = &quot;substr123&quot;;

int main()
{
    std::cout &lt;&lt; substr&lt;test, 4, 8&gt;::value &lt;&lt; '\n';
}
</code></pre>
<p>(gcc-4.7 erforderlich, Anpassung in 4.6 ist möglich).<br />
<a href="http://www.c-plusplus.net/forum/291117" rel="nofollow">Hier</a> hatte ich auch ein paar Techniken verwendet, die nützlich sein könnten.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2165044</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2165044</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Sat, 07 Jan 2012 21:46:48 GMT</pubDate></item><item><title><![CDATA[Reply to compiletime string validator generator on Sat, 07 Jan 2012 21:55:39 GMT]]></title><description><![CDATA[<blockquote>
<p>Ich wüsste nicht, warum es nicht möglich sein sollte. Den query könnte man natürlich nicht zur Compilezeit ausführen (macht ja auch wenig Sinn), aber man kann schonmal den Befehl in c++ (und dann in Maschinencode) übersetzen.<br />
Zitat:</p>
<p>...</p>
<p>Wie meinst du das? Eine Sprache die nur &quot;print string&quot; kann, beim compilen übersetzt wird und den string dann über ein code.exec() zur Laufzeit ausgibt? Es gäbe vielleicht die Möglichkeit, über ein static_assert eine Ausgabe beim compilen zu erzeugen... aber ich wüsste jetzt so spontan nicht, wie ich einen constexpr char substr[] aus einem anderen constexpr string generieren könnte...</p>
</blockquote>
<p>Na das meinte ich ja ungefähr.<br />
Mich hat interessiert wie es aussehen würde aus einem</p>
<pre><code class="language-cpp">constexpr const_string&lt; char &gt; cmd = &quot;print Hallo&quot;;
</code></pre>
<p>ein</p>
<pre><code class="language-cpp">std::cout &lt;&lt; &quot;Hallo&quot;;
</code></pre>
<p>zu bauen (und logischerweise zu kompilieren), da du ja meintest dass soetwas möglich ist.</p>
<p>Für mich ist die ganze Meta-Templatespielerei noch recht schwarze Magie.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2165047</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2165047</guid><dc:creator><![CDATA[Ethon]]></dc:creator><pubDate>Sat, 07 Jan 2012 21:55:39 GMT</pubDate></item><item><title><![CDATA[Reply to compiletime string validator generator on Sat, 07 Jan 2012 23:09:59 GMT]]></title><description><![CDATA[<p>Wie immer sehr kompetenter Beitrag, hab ne Weile gebraucht bis ich alles verstanden hatte (vor allem, um zu begreifen was make_index tun soll... ist es so deutlich schneller als mit der naiven Variante?).</p>
<p>camper schrieb:</p>
<blockquote>
<pre><code class="language-cpp">extern constexpr char test[] = &quot;substr123&quot;;
</code></pre>
</blockquote>
<p>Kannst du das <code>extern</code> bisschen erklären? Warum kann man test nur damit als template Parameter verwenden?</p>
<p><a class="plugin-mentions-user plugin-mentions-a" href="https://www.c-plusplus.net/forum/uid/26744">@Ethon</a>:</p>
<pre><code class="language-cpp">#include &lt;iostream&gt;

#include &quot;terminal.hpp&quot;
#include &quot;concat.hpp&quot;
#include &quot;repet.hpp&quot;

DEF_TERMINAL( Tprint , &quot;print&quot; )

struct anything
    : symbol
{
    constexpr anything( const_string&lt; char &gt; str , unsigned int begin = 0 )
        : symbol( str.size() ) ,
          m_str( str ) ,
          m_begin( begin )
    {
    }
    void print() const
    {
        std::cout &lt;&lt; m_str.m_begin + m_begin;
    }
    const_string&lt; char &gt; m_str;
    unsigned int m_begin;
};

struct statement
    : concat
    &lt;
        Tprint ,
        concat&lt; terminal&lt; ' ' &gt; , repet&lt; terminal&lt; ' ' &gt; &gt; &gt; ,
        anything
    &gt;
{
    template&lt; class ...ArgTypes &gt;
    constexpr statement( ArgTypes ...args )
        : concat
        &lt;
            Tprint ,
            concat&lt; terminal&lt; ' ' &gt; , repet&lt; terminal&lt; ' ' &gt; &gt; &gt; ,
            anything
        &gt;( args... )
    {
    }
    void exec() const
    {
        get&lt; 2 &gt;().print();
    }
};

int main()
{
    constexpr statement s( const_string&lt; char &gt;( &quot;print hello world&quot; ) );
    static_assert( s.valid() , &quot;&quot; );
    s.exec();
}
</code></pre>
<p>Braucht die files von dem mathparser. Außerdem wirst du erst eine Fehlermeldung bekommen, dass m_begin in const_string private ist, mach es einfach public.<br />
Diese Variante kommt natürlich nur mit einem &quot;print&quot; klar und gibt dann den Rest aus.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2165071</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2165071</guid><dc:creator><![CDATA[GorbGorb]]></dc:creator><pubDate>Sat, 07 Jan 2012 23:09:59 GMT</pubDate></item><item><title><![CDATA[Reply to compiletime string validator generator on Sat, 07 Jan 2012 23:55:13 GMT]]></title><description><![CDATA[<p>GorbGorb schrieb:</p>
<blockquote>
<p>Wie immer sehr kompetenter Beitrag, hab ne Weile gebraucht bis ich alles verstanden hatte (vor allem, um zu begreifen was make_index tun soll... ist es so deutlich schneller als mit der naiven Variante?).</p>
<p>camper schrieb:</p>
<blockquote>
<pre><code class="language-cpp">extern constexpr char test[] = &quot;substr123&quot;;
</code></pre>
</blockquote>
<p>Kannst du das <code>extern</code> bisschen erklären? Warum kann man test nur damit als template Parameter verwenden?</p>
</blockquote>
<p>Schnelligkeit ist nicht so sehr das Problem, Speicherverbrauch dagegen schon, und der nimmt bei linearer Implementierung ziemlich schnell zu.</p>
<p>Das extern gehört dahin, weil nur Zeiger auf Objekte mit externer Bindung Templateargumente sein können, deshalb können auch Stringliterale nicht direkt als Templateargumente verwendet werden.</p>
<p>Man könnte auch eine einfache Funktion schreiben</p>
<pre><code class="language-cpp">template &lt;std::ptrdiff_t... i&gt;
constexpr std::array&lt;char, sizeof...(i)+1&gt; substr_impl(const char* str, index_list&lt;i...&gt;)
{
    return std::array&lt;char, sizeof...(i)+1&gt;{ { str[i]..., 0 } };
}

template &lt;ptrdiff_t begin, ptrdiff_t end&gt;
constexpr std::array&lt;char,end-begin+1&gt; substr(const char* str)
{
    return substr_impl(str, typename shift_index_list&lt;make_index_list&lt;end - begin&gt;, begin&gt;::type());
}
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2165117</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2165117</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Sat, 07 Jan 2012 23:55:13 GMT</pubDate></item><item><title><![CDATA[Reply to compiletime string validator generator on Sun, 08 Jan 2012 01:12:58 GMT]]></title><description><![CDATA[<p>Ich seh grade dass man in static_assert einen string literal braucht... hatte erwartet dass es nur ein konstanter Ausdruck sein muss. Dann hat sich die Sache mit der Ausgabe über static_assert natürlich eh erledigt. (schade, das wäre witzig gewesen die Ausgabe eines Programms über die Fehlermeldungen des compilers laufen zu lassen)</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2165142</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2165142</guid><dc:creator><![CDATA[GorbGorb]]></dc:creator><pubDate>Sun, 08 Jan 2012 01:12:58 GMT</pubDate></item><item><title><![CDATA[Reply to compiletime string validator generator on Sun, 08 Jan 2012 02:09:44 GMT]]></title><description><![CDATA[<p>Wo wir gerade bei TMP-Magie sind, ich habe vorgestern eine kleine Compiletime-Bigint Lib geschrieben. Im Moment ist nur Addition, Shifts, Vergleichsoperatoren und ein min/max implementiert, aber das kann man ja relativ einfach erweitern...<br />
<a href="http://ideone.com/U7OzC" rel="nofollow">http://ideone.com/U7OzC</a><br />
to_string gibt derzeit nur Binärstrings zurück und wahrscheinlich kann man am Code vieles vereinfachen. Ich hab das um 3 Uhr morgens gemacht. <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f609.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--winking_face"
      title=";)"
      alt="😉"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/2165146</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2165146</guid><dc:creator><![CDATA[314159265358979]]></dc:creator><pubDate>Sun, 08 Jan 2012 02:09:44 GMT</pubDate></item><item><title><![CDATA[Reply to compiletime string validator generator on Sun, 08 Jan 2012 13:18:09 GMT]]></title><description><![CDATA[<p>314159265358979 schrieb:</p>
<blockquote>
<p>Wo wir gerade bei TMP-Magie sind, ich habe vorgestern eine kleine Compiletime-Bigint Lib geschrieben. Im Moment ist nur Addition, Shifts, Vergleichsoperatoren und ein min/max implementiert, aber das kann man ja relativ einfach erweitern...<br />
<a href="http://ideone.com/U7OzC" rel="nofollow">http://ideone.com/U7OzC</a><br />
to_string gibt derzeit nur Binärstrings zurück und wahrscheinlich kann man am Code vieles vereinfachen. Ich hab das um 3 Uhr morgens gemacht. <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f609.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--winking_face"
      title=";)"
      alt="😉"
    /></p>
</blockquote>
<p>Gegeben sei</p>
<pre><code class="language-cpp">#include &lt;cstddef&gt;

template &lt;typename T&gt; struct identity
{
    typedef T type;
};

template &lt;std::size_t... i&gt; struct index_list
    : identity&lt;index_list&lt;i...&gt;&gt; {};

template &lt;typename T&gt;       struct append_index_list
    : append_index_list&lt;typename T::type&gt; {};
template &lt;std::size_t... i&gt; struct append_index_list&lt;index_list&lt;i...&gt;&gt;
    : identity&lt;index_list&lt;0, ( i + 1 )...&gt;&gt; {};

template &lt;std::size_t N&gt; struct make_index_list
    : append_index_list&lt;make_index_list&lt;N - 1&gt;&gt; {};
template &lt;&gt;              struct make_index_list&lt;0&gt;
    : identity&lt;index_list&lt;&gt;&gt; {};

template &lt;char... c&gt; struct string
    : identity&lt;string&lt;c...&gt;&gt;
{
    static constexpr char value[] = { c..., '\0' };
};
template &lt;char... c&gt;
constexpr char string&lt;c...&gt;::value[];

template &lt;typename str, typename indexes&gt; struct substr
    : substr&lt;typename str::type, typename indexes::type&gt; {};
template &lt;typename str, std::size_t... i&gt; struct substr&lt;str, index_list&lt;i...&gt;&gt;
    : identity&lt;string&lt;str::value[i]...&gt;&gt; {};

#define C( s, x )        (x&lt;sizeof(s)?s[x]:'\0')
#define STR4( s, x )     C( s, x), C(s, x+1), C(s, x+2), C(s, x+3)
#define STR16( s, x )    STR4(   s, x), STR4(   s, x+4),    STR4(  s, x+8),     STR4(   s, x+12)
#define STR64( s, x )    STR16(  s, x), STR16(  s, x+16),   STR16( s, x+32),    STR16(  s, x+48)
#define STR256( s, x )   STR64(  s, x), STR64(  s, x+64),   STR64( s, x+128),   STR64(  s, x+192)
#define STR1024( s, x )  STR256( s, x), STR256( s, x+256),  STR256(s, x+512),   STR256( s, x+768)
#define STR4096( s, x )  STR1024(s, x), STR1024(s, x+1024), STR1024(s, x+2048), STR1024(s, x+3072)
#define STRING( x )      substr&lt;string&lt;STR4096(x,0), '\0'&gt;,make_index_list&lt;sizeof(x)&gt;&gt;::type

#include &lt;iostream&gt;
int main()
{
    std::cout &lt;&lt; STRING(&quot;12345&quot;)::value &lt;&lt; '\n';
}
</code></pre>
<p>Jetzt möchte ich eine Template-Metafunktion haben, die Strings direkt parst und ggf. Berechnungen anstellt, also z.B.</p>
<pre><code class="language-cpp">std::cout &lt;&lt; compute&lt;STRING(&quot;10+20+30&quot;)::value
</code></pre>
<p>sollte dann 60 ausgeben.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2165267</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2165267</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Sun, 08 Jan 2012 13:18:09 GMT</pubDate></item><item><title><![CDATA[Reply to compiletime string validator generator on Sun, 08 Jan 2012 13:41:40 GMT]]></title><description><![CDATA[<p>So blöd es klingt, aber einen Mathe-Parser kriege ich nicht mal mit &quot;normalen&quot; Funktionen ordentlich hin. Da kann ich einen über TMP erst recht nicht.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2165291</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2165291</guid><dc:creator><![CDATA[314159265358979]]></dc:creator><pubDate>Sun, 08 Jan 2012 13:41:40 GMT</pubDate></item></channel></rss>