#include <iostream>
#include <thread>
#include <vector>
#include <algorithm>
#include <cstdio>

struct S {
    S() {}

    void dowork( int i ) {
        for( unsigned j=0; j<100; ++j ) {
            //std::cout << i << " - " << j << "\n"; // will interleave with cout's from other threads
            printf( "%i - %i\n", i, j ); // has built-in mutex
        }
    }
};


int main()
{
    //std::vector<std::thread> threads; //  tag1
    std::vector<std::thread> threads( 20 ); // tag2 default ctor for threads creates a "deferred" 
    S obj;
    for( unsigned i=0; i<20; ++i ) {
        threads[i] = std::thread( &S::dowork, &obj, i ); // use with tag2
        //threads.push_back( std::thread( &S::dowork, &obj, i ) ); // use with tag1
    }
    for( auto & t : threads ) {
        t.join();
    }
    // std::for_each( threads.begin(),threads.end(), std::mem_fn( &std::thread::join ) );
}