Random C++ STL-only password generator for education
The code looks good. May be argument parsing could be done better, but in general this is solid simple password generator. There are things to mention though, but they mostly apply on reusability and expandability

Separate concerns

At the moment the main() function does quite a lot of things:


Setup random number generator
Parse program arguments
Generate password
Output it to the user


Encapsulate

I'm not saying reduce usability, but the password generator is very much like random number generator, it just gives out strings with random elements instead of bit blocks.

So, in my opinion, the following code would have sound design:

class random_password_generator
{
    //random engine and distribution
public:
    random_password_generator() 
    {
        //initialize
    }

    //random engine will decide rule of 5

    std::string operator()()
    {
        //create password
    }
}




Parsing arguments can be just a plain function. For complex cases may be using Boost.program_options would be better. 



Code Review

atoi(argv[++i]);


atoi is a C standard library function. stoi is a C++ function standard library. In general, C++ library is more compatible with concepts of C++ itself, whereas C library usually needs some wrappers to be usable with the rest of C++.

int length = 16;


My personal preference is to use unsigned int or std::size_t for things that cannot have negative values.

Do not use bind unless necessary

std::bind() might have problems that lambda can't solve, but I'm yet to encounter such problems. In general: use lambda for function objects unless you can't. The reason is that std::bind does heap allocation, type erasure, and possibly other stuff, whereas lambda is just anonymous object with operator().

Range loops

for (int i = 0; i &lt; length; i++)


The above also has a chance to fail in case you'll change the resizing part of the string. It is better to use range for loop:

for (char&amp; c: password)
{
    //assign
}


It will also remove the need to use at(), which does bounds checking, and in general frowned upon in release code.

Even better

Use standard algorithms. Since the functor generates random characters, code could just use std::generate(password.begin(), password.end(), generator).

Do not use std::endl

std::endl is not only a platform independent way to print newline. Printing newline is achieved with streaming '\n'. Even on windows ostream will deal with it. std::endl prints newline and flushes stream, which might cause detrimental performance hit in tight loops.

Don't use C style casts

(int) charset.size()


C style casts are much more dangerous, and compiler will not warn you if it does something dangerous. On the other hand, using one of C++ style casts will ensure compilation error in case something fishy is going on, except reinterpret_cast&lt;&gt;, which is fishy by definition.