<?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[Sequencepoint - Undefiniertes Verhalten - Variadisches Template]]></title><description><![CDATA[<p>Hoi,<br />
ich bastle mir gerade einen Wrapper um die Sqlite3 C-API.</p>
<p>Ein Teil des Codes:</p>
<pre><code>template&lt;typename&gt;
struct ColumnFetcher;

template&lt;&gt;
struct ColumnFetcher&lt;char const*&gt;
{
    static bool canFetch(Statement&amp; stmnt, int column)
    {
        return sqlite3_column_type(stmnt.get(), column) == SQLITE3_TEXT;
    }

    static char const* fetch(Statement&amp; stmnt, int column)
    {
        assert(canFetch(stmnt, column));
        return (char const*)sqlite3_column_text(stmnt.get(), column);
    }
};

template&lt;&gt;
struct ColumnFetcher&lt;std::string&gt;
{
    static bool canFetch(Statement&amp; stmnt, int column)
    {
        return ColumnFetcher&lt;char const*&gt;::canFetch(stmnt, column);
    }

    static std::string fetch(Statement&amp; stmnt, int column)
    {
        char const* ptr = ColumnFetcher&lt;char const*&gt;::fetch(stmnt, column);
        int numBytes = sqlite3_column_bytes(stmnt.get(), column);
        return std::string(ptr, ptr + numBytes);
    }
};

template&lt;&gt;
struct ColumnFetcher&lt;int&gt;
{
    static bool canFetch(Statement&amp; stmnt, int column)
    {
        return sqlite3_column_type(stmnt.get(), column) == SQLITE_INTEGER;
    }

    static int fetch(Statement&amp; stmnt, int column)
    {
        assert(canFetch(stmnt, column));
        return sqlite3_column_int(stmnt.get(), column);
    }
};

template&lt;typename... Types&gt;
std::tuple&lt;Types...&gt; fetchRow(Statement&amp; stmnt)
{
    int columnIndex = 0;
    return std::make_tuple(ColumnFetcher&lt;Types&gt;::fetch(stmnt, columnIndex++)...);
}
</code></pre>
<p>Jedenfalls jammert der GCC über das <em>columnIndex++</em>. Wie würde es denn korrekt aussehen? Mir fällt gerade dazu recht wenig ein ...</p>
<p>Danke und Grüße,<br />
Ethon</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/314520/sequencepoint-undefiniertes-verhalten-variadisches-template</link><generator>RSS for Node</generator><lastBuildDate>Sat, 01 Aug 2026 05:58:46 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/314520.rss" rel="self" type="application/rss+xml"/><pubDate>Tue, 05 Mar 2013 09:49:34 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Sequencepoint - Undefiniertes Verhalten - Variadisches Template on Tue, 05 Mar 2013 09:49:34 GMT]]></title><description><![CDATA[<p>Hoi,<br />
ich bastle mir gerade einen Wrapper um die Sqlite3 C-API.</p>
<p>Ein Teil des Codes:</p>
<pre><code>template&lt;typename&gt;
struct ColumnFetcher;

template&lt;&gt;
struct ColumnFetcher&lt;char const*&gt;
{
    static bool canFetch(Statement&amp; stmnt, int column)
    {
        return sqlite3_column_type(stmnt.get(), column) == SQLITE3_TEXT;
    }

    static char const* fetch(Statement&amp; stmnt, int column)
    {
        assert(canFetch(stmnt, column));
        return (char const*)sqlite3_column_text(stmnt.get(), column);
    }
};

template&lt;&gt;
struct ColumnFetcher&lt;std::string&gt;
{
    static bool canFetch(Statement&amp; stmnt, int column)
    {
        return ColumnFetcher&lt;char const*&gt;::canFetch(stmnt, column);
    }

    static std::string fetch(Statement&amp; stmnt, int column)
    {
        char const* ptr = ColumnFetcher&lt;char const*&gt;::fetch(stmnt, column);
        int numBytes = sqlite3_column_bytes(stmnt.get(), column);
        return std::string(ptr, ptr + numBytes);
    }
};

template&lt;&gt;
struct ColumnFetcher&lt;int&gt;
{
    static bool canFetch(Statement&amp; stmnt, int column)
    {
        return sqlite3_column_type(stmnt.get(), column) == SQLITE_INTEGER;
    }

    static int fetch(Statement&amp; stmnt, int column)
    {
        assert(canFetch(stmnt, column));
        return sqlite3_column_int(stmnt.get(), column);
    }
};

template&lt;typename... Types&gt;
std::tuple&lt;Types...&gt; fetchRow(Statement&amp; stmnt)
{
    int columnIndex = 0;
    return std::make_tuple(ColumnFetcher&lt;Types&gt;::fetch(stmnt, columnIndex++)...);
}
</code></pre>
<p>Jedenfalls jammert der GCC über das <em>columnIndex++</em>. Wie würde es denn korrekt aussehen? Mir fällt gerade dazu recht wenig ein ...</p>
<p>Danke und Grüße,<br />
Ethon</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2304386</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2304386</guid><dc:creator><![CDATA[Ethon]]></dc:creator><pubDate>Tue, 05 Mar 2013 09:49:34 GMT</pubDate></item><item><title><![CDATA[Reply to Sequencepoint - Undefiniertes Verhalten - Variadisches Template on Tue, 05 Mar 2013 10:03:29 GMT]]></title><description><![CDATA[<pre><code class="language-cpp">template&lt;typename... Types&gt;
std::tuple&lt;Types...&gt; fetchRow(Statement&amp; stmnt)
{
    int columnIndex = 0;
    return std::tuple&lt;Types...&gt;{ColumnFetcher&lt;Types&gt;::fetch(stmnt, columnIndex++)...};
}
</code></pre>
<p>Der Aufruf von std::make_tuple wäre ein normaler Funktionsaufruf, und die Auswertung von Funktionsargumenten ist bekanntermaßen ungeordnet.</p>
<pre><code class="language-cpp">std::tuple&lt;Types...&gt;(ColumnFetcher&lt;Types&gt;::fetch(stmnt, columnIndex++)...);
</code></pre>
<p>(runde Klammern)<br />
wäre ebenso ein normaler Funktionsaufruf mit dem gleichen Problem.</p>
<pre><code class="language-cpp">std::tuple&lt;Types...&gt;{ColumnFetcher&lt;Types&gt;::fetch(stmnt, columnIndex++)...};
</code></pre>
<p>Führt zwar auch zum Aufruf des Konstruktors, ist aber gleichzeitig eine List-Initialisierung.<br />
8.5.4/4 bestimmt, das hier die syntaktische Form die Auswertungsreihenfolge bestimmt. Die Idee war, dass die Semantik nicht davon abhängen sollte (und also generischer Code sich nicht darum zu kümmern brauch), wie die Initialisierung letztlich durchgeführt wird (per normalem Konstruktor, per initializer_list-Konstruktor oder per Aggregatinitialisierung - die letzten beiden Fälle garantieren diese Ausführungsreihenfolge sowieso).</p>
<p>In diesem speziellen Fall könnte man das auch noch anders lösen, indem die Indizes als Templateargument geliefert werden.</p>
<pre><code class="language-cpp">template&lt;typename... Types, int... i&gt;
std::tuple&lt;Types...&gt; fetchRow_(Statement&amp; stmnt, index_list&lt;i...&gt;) // index_list wurde schon oft gezeigt
{
    return std::make_tuple(ColumnFetcher&lt;Types&gt;::fetch(stmnt, i)...);
}

template&lt;typename... Types&gt;
std::tuple&lt;Types...&gt; fetchRow(Statement&amp; stmnt)
{
    return fetchRow_&lt;Types...&gt;(stmnt, make_index_list&lt;sizeof...(Types)&gt;());
}
</code></pre>
<p>Auf einer sehr theoretischen Ebene gibt das dem Compiler mehr Freiheit beim Optimieren.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2304387</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2304387</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Tue, 05 Mar 2013 10:03:29 GMT</pubDate></item><item><title><![CDATA[Reply to Sequencepoint - Undefiniertes Verhalten - Variadisches Template on Tue, 05 Mar 2013 10:16:48 GMT]]></title><description><![CDATA[<p>Also, mit deiner ersten Lösung warnt der GCC weiterhin und wertet dummerweise auch noch von rechts nach links aus.</p>
<p>Ich versuch's mal mit der zweiten, danke!</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2304397</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2304397</guid><dc:creator><![CDATA[Ethon]]></dc:creator><pubDate>Tue, 05 Mar 2013 10:16:48 GMT</pubDate></item><item><title><![CDATA[Reply to Sequencepoint - Undefiniertes Verhalten - Variadisches Template on Tue, 05 Mar 2013 10:31:25 GMT]]></title><description><![CDATA[<p>Ethon schrieb:</p>
<blockquote>
<p>Also, mit deiner ersten Lösung warnt der GCC weiterhin</p>
</blockquote>
<p>kann ich bestätigen.</p>
<blockquote>
<p>und wertet dummerweise auch noch von rechts nach links aus.</p>
</blockquote>
<p>das nicht, liegt aber ggf. am jeweiligen Code.</p>
<p>clang warnt nicht.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2304407</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2304407</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Tue, 05 Mar 2013 10:31:25 GMT</pubDate></item><item><title><![CDATA[Reply to Sequencepoint - Undefiniertes Verhalten - Variadisches Template on Tue, 05 Mar 2013 16:41:53 GMT]]></title><description><![CDATA[<p>Mit zweiter Lösung klappt es super, vielen Dank dir. <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/2304524</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2304524</guid><dc:creator><![CDATA[Ethon]]></dc:creator><pubDate>Tue, 05 Mar 2013 16:41:53 GMT</pubDate></item><item><title><![CDATA[Reply to Sequencepoint - Undefiniertes Verhalten - Variadisches Template on Tue, 05 Mar 2013 18:45:22 GMT]]></title><description><![CDATA[<p>Ethon schrieb:</p>
<blockquote>
<p>Mit zweiter Lösung klappt es super, vielen Dank dir. <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>Kannst du mal vollständigen Code posten, der von gcc fehlerhaft umgesetzt wird?<br />
Die o.g. Regel wurde in ihrer finalen Form erst im <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1030" rel="nofollow">März 2011</a> aufgenommen, so dass Versionen vor 4.7 diese im Prinzip nicht unterstützen können.<br />
gcc scheint allerdings auch der <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#430" rel="nofollow">einzige</a> Compiler zu sein, der dieses Problem zeigt(e).</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2304572</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2304572</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Tue, 05 Mar 2013 18:45:22 GMT</pubDate></item><item><title><![CDATA[Reply to Sequencepoint - Undefiniertes Verhalten - Variadisches Template on Wed, 06 Mar 2013 08:10:44 GMT]]></title><description><![CDATA[<p>Klar, hier ist er:</p>
<pre><code>#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;tuple&gt;
#include &lt;cassert&gt;
#include &lt;sqlite3.h&gt;

using namespace std;

class Sqlite3Error
{
public:
    Sqlite3Error(std::string msg, int errorCode, std::string sqliteErrorMsg)
    {

    }
};

namespace Sqlite3Detail
{
    sqlite3* openDb(char const* dbFile)
    {
        sqlite3* handle = nullptr;
        int ec = sqlite3_open(dbFile, &amp;handle);
        if(ec != SQLITE_OK)
        {
            throw Sqlite3Error(&quot;Failed to open database&quot;, ec, sqlite3_errmsg(handle));
        }

        return handle;
    }

    sqlite3_stmt* prepareStatement(sqlite3* handle, std::string const&amp; statement)
    {
        sqlite3_stmt* prepared = nullptr;
        char const* unused = nullptr;
        int ec = sqlite3_prepare_v2(handle, statement.c_str(), statement.size() + 1,
            &amp;prepared, &amp;unused);
        if(ec != SQLITE_OK)
        {
            throw Sqlite3Error(&quot;Failed to compile statement&quot;, ec, sqlite3_errmsg(handle));
        }

        return prepared;
    }
}

class Handle
{
private:
    sqlite3* m_db;

    void dispose()
    {
        if(m_db)
            sqlite3_close(m_db);
    }

    // Forbid copies.
    Handle(Handle const&amp;) = delete;
    Handle&amp; operator=(Handle const&amp;) = delete;

public:
    explicit Handle(char const* dbFile)
        : m_db(Sqlite3Detail::openDb(dbFile))
    { }

    ~Handle()
    {
        dispose();
    }

    Handle(Handle&amp;&amp; other)
        : m_db(other.m_db)
    {
        other.m_db = nullptr;
    }

    Handle&amp; operator=(Handle&amp;&amp; other)
    {
        m_db = other.m_db;
        other.m_db = nullptr;
        return *this;
    }

    sqlite3* get()
    {
        return m_db;
    }
};

class Statement
{
private:
    sqlite3_stmt* m_statement;

    void dispose()
    {
        if(m_statement)
            sqlite3_finalize(m_statement);
    }

    // Forbid copies.
    Statement(Statement const&amp;) = delete;
    Statement&amp; operator=(Statement const&amp;) = delete;

public:
    Statement(Handle&amp; db, std::string const&amp; statement)
        : m_statement(Sqlite3Detail::prepareStatement(db.get(), statement))
    { }

    Statement(Statement&amp;&amp; other)
        : m_statement(other.m_statement)
    {
        other.m_statement = nullptr;
    }

    Statement&amp; operator=(Statement&amp;&amp; other)
    {
        m_statement = other.m_statement;
        other.m_statement = nullptr;
        return *this;
    }

    sqlite3_stmt* get()
    {
        return m_statement;
    }

    void reset()
    {
        int ec = sqlite3_reset(get());
        if(ec != SQLITE_OK)
        {
            throw Sqlite3Error(&quot;Failed to reset statement&quot;, ec, sqlite3_errstr(ec));
        }
    }

    bool step()
    {
        int ec = sqlite3_step(get());
        if(ec == SQLITE_ROW)
            return true;
        if(ec == SQLITE_DONE)
            return false;

        throw Sqlite3Error(&quot;Failed to execute statement&quot;, ec, sqlite3_errstr(ec));
    }
};

template&lt;typename&gt;
struct ColumnFetcher;

template&lt;&gt;
struct ColumnFetcher&lt;char const*&gt;
{
    static bool canFetch(Statement&amp; stmnt, int column)
    {
        return sqlite3_column_type(stmnt.get(), column) == SQLITE3_TEXT;
    }

    static char const* fetch(Statement&amp; stmnt, int column)
    {
        return (char const*)sqlite3_column_text(stmnt.get(), column);
    }
};

template&lt;&gt;
struct ColumnFetcher&lt;std::string&gt;
{
    static bool canFetch(Statement&amp; stmnt, int column)
    {
        return ColumnFetcher&lt;char const*&gt;::canFetch(stmnt, column);
    }

    static std::string fetch(Statement&amp; stmnt, int column)
    {
        char const* ptr = ColumnFetcher&lt;char const*&gt;::fetch(stmnt, column);
        int numBytes = sqlite3_column_bytes(stmnt.get(), column);
        return std::string(ptr, ptr + numBytes);
    }
};

template&lt;&gt;
struct ColumnFetcher&lt;int&gt;
{
    static bool canFetch(Statement&amp; stmnt, int column)
    {
        return sqlite3_column_type(stmnt.get(), column) == SQLITE_INTEGER;
    }

    static int fetch(Statement&amp; stmnt, int column)
    {
        return sqlite3_column_int(stmnt.get(), column);
    }
};

template&lt;typename... Types&gt;
std::tuple&lt;Types...&gt; fetchRow(Statement&amp; stmnt)
{
    int columnIndex = 0;
    return std::tuple&lt;Types...&gt;{ColumnFetcher&lt;Types&gt;::fetch(stmnt, columnIndex++)...};
}

int main()
{
    Handle handle(&quot;Dummy.db&quot;);
    Statement stmnt(handle, &quot;CREATE TABLE IF NOT EXISTS users (uname TEXT PRIMARY KEY,pass TEXT NOT NULL,activated INTEGER)&quot;);
    std::cout &lt;&lt; &quot;Has data ? &quot; &lt;&lt; (stmnt.step() ? &quot;yes&quot; : &quot;no&quot;) &lt;&lt; std::endl;
    stmnt.reset();

    Statement stmnt2(handle, &quot;INSERT INTO users VALUES ('Flo', 'password', 1)&quot;);
    std::cout &lt;&lt; &quot;Has data ? &quot; &lt;&lt; (stmnt2.step() ? &quot;yes&quot; : &quot;no&quot;) &lt;&lt; std::endl;

    Statement stmnt3(handle, &quot;SELECT * FROM users&quot;);
    std::cout &lt;&lt; &quot;Has data ? &quot; &lt;&lt; (stmnt3.step() ? &quot;yes&quot; : &quot;no&quot;) &lt;&lt; std::endl;
    auto row = fetchRow&lt;std::string, std::string, std::string&gt;(stmnt3);
    std::cout &lt;&lt; &quot;uname: &quot; &lt;&lt; std::get&lt;0&gt;(row) &lt;&lt; std::endl;
    std::cout &lt;&lt; &quot;pass: &quot; &lt;&lt; std::get&lt;1&gt;(row) &lt;&lt; std::endl;
    std::cout &lt;&lt; &quot;activated: &quot; &lt;&lt; std::get&lt;2&gt;(row) &lt;&lt; std::endl;
    std::cout &lt;&lt; &quot;Has data ? &quot; &lt;&lt; (stmnt3.step() ? &quot;yes&quot; : &quot;no&quot;) &lt;&lt; std::endl;

    std::cerr &lt;&lt; &quot;End\n&quot;;
}
</code></pre>
<p>Erwartet:</p>
<blockquote>
<p>uname: Flo<br />
pass: password<br />
activated: 1</p>
</blockquote>
<p>Ausgabe:</p>
<blockquote>
<p>uname: 1<br />
pass: password<br />
activated: Flo</p>
</blockquote>
]]></description><link>https://www.c-plusplus.net/forum/post/2304635</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2304635</guid><dc:creator><![CDATA[Ethon]]></dc:creator><pubDate>Wed, 06 Mar 2013 08:10:44 GMT</pubDate></item><item><title><![CDATA[Reply to Sequencepoint - Undefiniertes Verhalten - Variadisches Template on Wed, 06 Mar 2013 08:28:32 GMT]]></title><description><![CDATA[<p>Deine Move-Assignment Operatoren sehen mir allesamt falsch aus. Sie disposen *this nicht.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2304637</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2304637</guid><dc:creator><![CDATA[Kellerautomat]]></dc:creator><pubDate>Wed, 06 Mar 2013 08:28:32 GMT</pubDate></item><item><title><![CDATA[Reply to Sequencepoint - Undefiniertes Verhalten - Variadisches Template on Wed, 06 Mar 2013 08:39:44 GMT]]></title><description><![CDATA[<p>Kellerautomat schrieb:</p>
<blockquote>
<p>Deine Move-Assignment Operatoren sehen mir allesamt falsch aus. Sie disposen *this nicht.</p>
</blockquote>
<p>Jap, und noch ein paar andere Maccken. Der Code war ja nur zum Rumspielen mit Sqlite da, so benutze icch es aucgh nicht im Projekt. <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/2304639</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2304639</guid><dc:creator><![CDATA[Ethon]]></dc:creator><pubDate>Wed, 06 Mar 2013 08:39:44 GMT</pubDate></item><item><title><![CDATA[Reply to Sequencepoint - Undefiniertes Verhalten - Variadisches Template on Wed, 06 Mar 2013 22:28:42 GMT]]></title><description><![CDATA[<p>Ich kann das Problem mit 4.7.2 und 4.8 alpha nachvollziehen. Ein <a href="http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51253" rel="nofollow">gcc-bug</a> existiert.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2304860</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2304860</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Wed, 06 Mar 2013 22:28:42 GMT</pubDate></item><item><title><![CDATA[Reply to Sequencepoint - Undefiniertes Verhalten - Variadisches Template on Thu, 07 Mar 2013 08:59:35 GMT]]></title><description><![CDATA[<p>Wow, das erste Mal dass der Compiler schuld ist und nicht ich. :p</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2304932</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2304932</guid><dc:creator><![CDATA[Ethon]]></dc:creator><pubDate>Thu, 07 Mar 2013 08:59:35 GMT</pubDate></item></channel></rss>