nonstd:: non standard classes I am looking for people's opinions on my use of a set of non standard "standard classes". Basically I am working on a 'modern' C++ Lexical Analyser and Parser Generator duo to replace flex and GNU Bison which will work as a library and tool combination.

I have a number of non standard extensions of std library classes. The reason I am needing these nonstandard classes is to be able to express algorithms more succinctly and nearer the mathematical equivalents.

Here's a vector class that allows extension via operator[], which also has a generic Base parameter, allowing the vector to be based at 1 rather than zero, for example. And I return indices as size_t's rather than iterators as indexes are more useful in a traditional mathematical sense.

//
//  vector.h - auto sizing 'vector' class
//
//  Copyright (c) 2015-2016 Aaron Nathaniel Gray under the MIT License
//

#include &lt;vector&gt;
#include &lt;iostream&gt;

template&lt;typename T, size_t Base = 0&gt;
class vector : public std::vector&lt;T&gt; {
public:
    vector() : std::vector&lt;T&gt;() {}
    vector(const std::initializer_list&lt;T&gt; il) : std::vector&lt;T&gt;(il) {}
    ~vector() {}

    iterator last() { return end() - 1; }
    const_iterator clast() const { return end - 1; }

    size_t size() const { return std::vector&lt;T&gt;::size(); }
    void resize(size_t _size) { std::vector&lt;T&gt;::resize(_size); }
    T&amp; operator [] (size_t index) {
        if (index + 1 - Base &gt; size())
            resize(index + 1 - Base);
        return std::vector&lt;T&gt;::operator[](index - Base);
    }
    const T operator [] (size_t index) const {
        if (index + 1 - Base &lt;= size())
            return std::vector&lt;T&gt;::operator[](index - Base);
        else
            return T();
    }
    signed find(const T&amp; value) {
        auto i = std::find(cbegin(), cend(), value);
        if (i != cend())
            return i - cbegin() + Base;
        else
            return -1;
    }
    size_t add(const T value = T()) {
        push_back(value);
        return size() - 1 + Base;
    }
    std::string toString() const;
};

template&lt;typename T, size_t Base = 0&gt;
std::string vector&lt;T, Base&gt;::toString() const {
    std::stringstream ss;

    for (size_t element = Base; element &lt; size() + Base; ++element) {
        ss &lt;&lt; (*this)[element];
        if (element &lt; size() + Base)
            ss &lt;&lt; ",";
        ss &lt;&lt; std::endl;
    }

    return ss.str();
}


I am wondering whether to use the namespace nonstd::vector.

I also have non-standard set, deque, and a very extensive bitset class.

Example:

nonstd::vector&lt;size_t&gt; accept;

for(auto state : states) {

    .... accept = ....

    this-&gt;accept[state-&gt;index] = accept;
}


Here, state-&gt;index may not be sequential or contiguous and maximum value not known, so push_back will not work.

And a find example:

nonstd::vector&lt;Production*&gt; productions;

...

size_t productionIndex = production.find(aProduction);
Standard classes and derivation

If a class does not have a virtual destructor it is not supposed to be derived from. Before we got the finally key word this was the indicator you were supposed to use before deriving from a class.

But its safe unless you start taking pointers to your class. So to make sure it is not used incorrectly you should put it in a private context (so nobody else can use it apart from your library).

Inheriting functions.

You don't need to copy functions if they have the same name (that's the point of inheriting).

size_t size() const { return std::vector&lt;T&gt;::size(); }
void resize(size_t _size) { std::vector&lt;T&gt;::resize(_size); }


Don't need these. You automatically inherit them.

Inheriting Constructors.

You can use the using clause to inherit all the constructors.

vector() : std::vector&lt;T&gt;() {}
vector(const std::initializer_list&lt;T&gt; il) : std::vector&lt;T&gt;(il) {}
~vector() {}


Can be replaced with:

using std::vector::vector;


Identifiers with leading underscore.

Don't use them.

void resize(size_t _size)
                   ^^^^^


DO you know the rules about a leading underscore. I do (you got it correct). But can you assume that all the people reading your code know (you can't and most get it wrong). So prefer not to use a leading underscore on your identifiers.

Operator[] is supposed to be fast

The operator[] is an unchecked access into the data. You use this when you know that your index is guaranteed correct. We also have a checked access at() which is used when you can't guarantee that your index is in range.

T&amp; operator [] (size_t index) {
    if (index + 1 - Base &gt; size())
        resize(index + 1 - Base);
    return std::vector&lt;T&gt;::operator[](index - Base);
}
const T operator [] (size_t index) const {
    if (index + 1 - Base &lt;= size())
        return std::vector&lt;T&gt;::operator[](index - Base);
    else
        return T();
}


Your operator[] is severely restricting the performance of your code for people that know that their access is good.

for(int loop=0;loop &lt; v.size(); ++loop)
{
    doStuff(v[loop]);  // Why do I need to check loop is in bounds
                       // each time? It is guaranteed to be in bounds
                       // by the context.
}


When people use operator[] they have already checked (or by context guranteed) that the index is in bounds. You should not be checking. You should provide an alternative function that checks and resizes.

find does not return an iterator

It seems strange that find does not return an iterator.

signed find(const T&amp; value) {
    auto i = std::find(cbegin(), cend(), value);
    if (i != cend())
        return i - cbegin() + Base;
    else
        return -1;
}


What's all this pointer maths.

        return i - cbegin() + Base;


Use the standard functions.

    return std::distance(cbegin(), i) + Base;


Constructing a string is easy

Your toString() function is bad as all that work can be done using the std::string constructors (also the standard library uses to_string() you should follow the same convention).

std::string to_string() const
{
    return std::string(cbegin(), cend());
}


Note: this does nothing.

    ss &lt;&lt; std::endl;


You should probably never use std::endl. It is actually very rare that you want to flush a stream (they flush themselves at the best times anyway being a human you will just make the code in-efficient by trying to overcompensate).

Namespace

You should definitely put your code into its own namespace. The name vector is just too common.

Sure nonstd seems like a fine name.

Personally I use an initial uppercase letter for all user defined types and namespaces. This allows me to quickly spot an object from type.

namespace ThorsAnvil
{
    class BlaBla
    {
        public:
            BlaBla(int x);
    };
    int bla(int y);
}


int main()
{
    namespace TA = ThorsAnvil;
    int data1 = 15 + TA::BlaBla(15); // I constructed an object here.
    int data2 = 16 + TA::bla(15);    // I called a function here.          
}


So I would call your stuff.

namespace NonStd
{
    template&lt;typename T&gt;
    class Vector { /* STUFF */};
};

template&lt;typename T&gt;
#if SomeNormalSituation
using Vec = NonStd::Vector&lt;T&gt;;
#else
using Vec = std::vector&lt;T&gt;;
#endif;

int main()
{
    Vec&lt;char&gt;   data;
}


Idea

Overall find.


  A vector class that allows extension via operator [] which also has a generic Base parameter allowing the vector to be based at 1 rather than zero for example. 


Your crazy this is going to cause you so many issues. CS people are so used to their arrays being zero based that any other number is just going to cause errors.

Thoughts


  Basically I am working on a 'modern' C++ Lexical Analyser and Parser Generator duo to replace flex and GNU Bison


Hmm. I love flex/bison. Use them all the time. It will be hard to replace something that is already near perfection. There is a reason why nobody has tried to improve them in years (and all attempts to replace them have failed).