Variadic function to find the first matching (string) argument in a larger array Playing around with parsing a data buffer I wrote a small search function to find the first complete match out of a set of (string) arguments.

The (simplified) buffer class with the find function:

// buffer_simple.hpp
#pragma once

#include &lt;cstddef&gt;
#include &lt;utility&gt;

template &lt;typename T, size_t S&gt;
class buffer {
public:
    constexpr buffer() {}
    template &lt;size_t Si&gt;
    constexpr buffer(const T (&amp;arr)[Si]) {
        for (size_t i = 0, l = (S &lt; Si ? S : Si); i &lt; l; ++i) {
            values[i] = arr[i];
        }
    }

    /**
     * Find the first matching array in a larger array and return the argument index and buffer end index of the match.
     * @param   str One or many strings to search for
     * @returns std::pair&lt;argument index, end of match index in buffer&gt;
     */
    template &lt;size_t... SS&gt;
    constexpr std::pair&lt;int, size_t&gt; find_first(const T (&amp;...str)[SS]) const {
        size_t matching[] { (SS - 1)... }; // Amount of remaining 'characters to match'
        for (size_t i = 0; i &lt; S; ++i) { // Loop over the dataset
            int mi = 0;
            ((matching[mi++] = (str[(SS - 1) - matching[mi]] == values[i]) ? (matching[mi] - 1) : ((str[0] == values[i]) ? (SS - 2) : (SS - 1) )), ...); // Nasty pseudo loop for width first search
            for (mi = 0; mi &lt; sizeof...(SS); ++mi) { // See if we have any full matches
                if (matching[mi] == 0) return { mi, i };
            }
        }
        return { -1, 0 };
    }

    constexpr T&amp; operator[](const size_t i) { return values[i]; }
    constexpr const T&amp; operator[](const size_t i) const { return values[i]; }
private:
    T values[S] {0};
};


An example use case:

#include &lt;iostream&gt;
#include "buffer_simple.hpp"

buffer&lt;char, 256&gt; b { "find mefind me:gehoehgioewghowieanother string:" };

int main () {
    const auto result = b.find_first("find me:", "bla", "another string:");
    // switch (result.first) {
    // case 0:
    //     break;
    // case 1:
    //     break;
    // case 2:
    //     break;
    // }
    std::cout &lt;&lt; "Result index: " &lt;&lt; result.first &lt;&lt; ", offset: " &lt;&lt; result.second &lt;&lt; std::endl;
}


This will return:

Result index: 0, offset: 14

Despite the extremely nasty fold expression this actually works. During runtime that is. As a test I tried declaring the buffer and search result constexpr and things blew up with GCC reporting an Array out of bounds error. I'm curious to see which other pitfalls might be lurking.
Good stuff!

I only see one big issue (which is actually what's preventing you from using this as a constexpr).

Errors:

UB: Unsequenced modification

matching[mi++] = (str[(SS - 1) - matching[mi]]
         ^^                               ^^


Which value does mi take for that second indexing? The C++ standard says: either the pre or post increment value is legal. You have undefined behavior here.

You can solve this by separating out the mi incrementation as a separate statement. Using the evil comma operator would allow you to do it as a fairly small modification of your existing code:

(
  ((matching[mi] = (str[(SS - 1) - matching[mi]] == values[i])
     ? (matching[mi] - 1) 
     : ((str[0] == values[i]) ? (SS - 2) : (SS - 1))
  ), ++mi), 
...);


This actually makes the constexpr version work!

Style


I think find_first should be a free-floating function, since you already have the [] accessors. 
I would definitely try to format that fold expression in a more readable manner. See my version of it above for an example.


Improvements


Add a template deduction guide:


Something like this:

template&lt;typename T, size_t LEN&gt;
buffer(const T(&amp;)[LEN]) -&gt; buffer&lt;T, LEN&gt;;


So then your declare buffers in a cleaner manner, and have the buffer be perfectly sized:

buffer&lt;char, 256&gt; b { "find mefind me:gehoehgioewghowieanother string:" };
//becomes
buffer b { "find mefind me:gehoehgioewghowieanother string:" };