Entries:
Comments:
Posts:

Loading User Information from Channel 9

Something went wrong getting user information from Channel 9

Latest Achievement:

Loading User Information from MSDN

Something went wrong getting user information from MSDN

Visual Studio Achievements

Latest Achievement:

Loading Visual Studio Achievements

Something went wrong getting the Visual Studio Achievements

Comments

Joshua Burkholder Burkholder
  • C9 Lectures: Stephan T Lavavej - Advanced STL, 1 of n

    @new2stl:Thanks for the information.  I will use the intrin.h header.

    Unfortunately, the machines that I'm writing for don't seem to have the AVX instruction set and its 256 bit registers.  Our machines are about three years old ... and it seems that AVX is relatively new.

    I am new to SSE.  The only info that I have read is the couple of MSDN Help webpages about MMX/SSE intrinsics and the one GCC webpage that I could find.  Where can I learn about how to program for the SSE instruction sets?  What are the good book titles?  What are the good websites/tutorials?

    FYI:  The reason that I am making copies of images is that I am at the start of a research project where I will get video streams from a couple of cameras.  I need to send each video stream to a couple of real-time algorithms that will execute concurrently in separate threads.  Since I don't know how destructive each algorithm will be to the image buffer, I just have another thread capture the images (i.e. fill the image buffer), make copies, and then let those algorithm threads loose on the copies ... where they can destructively edit those copies in complete isolation.  The real-time algorithms have changed a few times, so this way I have a system that works without the chance of one one thread stomping on another.  I'm sure that I'll revisit this copying-images code at the end of the project ... but by then, all the other algorithms will have been decided upon (and hopefully, set in stone).

     

    Thanks Again,
    Joshua Burkholder

  • C9 Lectures: Stephan T Lavavej - Advanced STL, 1 of n

    @STL:


    Burkholder> 5) What improvements can be made to my loop unrolling code at the end of this post?

    Consider using SSE, etc. Video processing is a perfect scenario for vectorization.

    (Of course, for simple copying, just use memcpy()/memmove(). In fact, our implementation of std::copy() calls memmove() when it can get away with it - something I'm very likely to cover in future parts.)

    Thanks for the AWESOME suggestions!!!  SSE, memcpy(), and memmove() are amazing!

    I'm a complete newbie to SSE ... but WOW ... it seems like using one instruction to load multiple floating point values into a 128-bit register and then using another instruction to store those values is a quicker way to go.  I have a few questions on SSE:

    1) Since I'm a newbie to SSE, I used the following type of code to copy memory from one place to another:

    #include <emmintrin.h>
    ...
    size_t const image_size = 640 * 480 * 3;
    double * image_buffer = new double[ image_size ];
    double * image_1 = new double[ image_size ];
    double * image_2 = new double[ image_size ];
    ...
    capture_image( image_buffer, image_size );
    ...
    __m128d sse_register;
    
    // Since two 64-bit doubles fit into one 128-bit sse register,
    // then our delta is 2.
    size_t const delta = 2;
    for ( size_t i = 0; i < image_size; i += delta ) {
        sse_register = _mm_load_pd( &image_buffer[ i ] );
        _mm_store_pd( &image_1[ i ], sse_register );
        _mm_store_pd( &image_2[ i ], sse_register );
    }
    In this case, is this the correct way to use SSE?  Or is there a better way?

    2) The following "normal" type of code (i.e. no _mm_xxxx_pd() stuff) also compiled and ran:

    #include <emmintrin.h>
    ...
    size_t const image_size = 640 * 480 * 3;
    double * image_buffer = new double[ image_size ];
    double * image_1 = new double[ image_size ];
    double * image_2 = new double[ image_size ];
    ...
    capture_image( image_buffer, image_size );
    ...
    // Since 128-bits is 2 * 64-bits, then ...
    size_t const img_size = image_size / 2;
    __m128 const * img_buffer = reinterpret_cast< __m128 const * >( &image_buffer[ 0 ] );
    __m128 * img_1 = reinterpret_cast< __m128 * >( &image_1[ 0 ] );
    __m128 * img_2 = reinterpret_cast< __m128 * >( &image_2[ 0 ] );
    for ( size_t i = 0; i < img_size; ++i ) {
        img_1[ i ] = img_buffer[ i ];
        img_2[ i ] = img_buffer[ i ];
    }
    
    Will this type of code (i.e. using __m128d * the same way I would double * or any other pointer) be valid in the future?  Or is this something that works in VS2010, but might not work in future versions?  ... If this will work in future versions, then what's up with all that _mm_xxxx_pd() stuff?

    3) I have no idea if I'm writing good or bad SSE code.  What are the suggested tutorials?  Are there any good books?

    Lastly, memcpy() and memmove() were faster at copying a single image than anything that I could write ... even with SSE and loop unrolling.  I could only beat memcpy() and memmove() when I took into account my specific situation ... copying a single image buffer into two images ... where I could use a single for-loop for both images (as above), vice a separate loop for each image.  So my question is:

    4) What is the "secret sauce" in memcpy() and memmove() that makes them so much faster?  Is the implementation of VS2010's memcpy() or memmove() available?  If so, where can I find that code?

    Definitely cover memmove() when you cover std::copy().

     

    Thanks In Advance,
    Joshua Burkholder

     

  • C9 Lectures: Stephan T Lavavej - Advanced STL, 1 of n

    Based on the previous STL videos and my interest in using templates to unroll loops, I have the following questions:

    1) What is the equivalent VS2010 C++ flag that corresponds to g++'s -ftemplate-depth=n ( http://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Dialect-Options.html#index-ftemplate_002ddepth-156 )?  Can this flag be set in the Visual Studio's Project/Properties/Configuration Properties dialog box (or some other dialog box) or just at the command line?

    2) Since C++0x's maximum template instantiation depth seems to be implementation dependent ( http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3225.pdf - Section 14.7.1 - Point 14 - Page 372), what is the maximum template instantiation depth of VS2010's templates?  Or is it template parameter dependent (i.e. compile-time stack dependent)?

    3) At compile-time, is there any way (even some weird compiler-dependent macro) to determine how deep into template instantiations we are without keeping track of that depth ourselves?

    4) for-loops seem to unroll themsleves if the conditional expression can be determined at compile-time and if the number of iterations are small enough.  What is the maximum number of iterations that still allow for-loops to unroll?  In others words, when does for-loop unrolling end and assembly jumps begin?

    5) What improvements can be made to my loop unrolling code at the end of this post?

    Background:
    Previously, I asked if we could cover loop unrolling (esp. for assignment statements).  Normally, if I needed to repeatedly perform a few hundred thousand assignment statements (i.e. copying the buffer of images or video frames for processing) and I wanted to minimize the impact of the "i < size" and "++i" in that for-loop, then I would just write out a for-loop with a bunch of assignment statements in the for-loop body using a script and then copy & paste that code into the relevent cpp file by hand.  Of course, this manual for-loop unrolling assumed that the size of the loops (i.e. the size of the images or video frames) weren't going to change from one compilation to another.  A few weeks back, I had to come up with something a little easier to work with since I was going to be dealing with a number of different buffer sizes (all still known at compile time ... no run-time querying).  With the help of pages 314-318 of C++ Templates: The Complete Guide, I ended up writing something like the following:

    #include <cstddef>
    #include <iostream>
    
    using namespace std;
    
    //=========================================================
    
    #ifdef _MSC_VER
    #define INLINE __forceinline
    #else
    #define INLINE inline
    #endif
    
    //primary template:
    template < typename ACTION_TYPE, typename TYPE, size_t n >
    struct unroll_loop_t {
        INLINE static void call ( TYPE * destination_ptr, TYPE const * source_ptr ) {
            ACTION_TYPE::call( destination_ptr, source_ptr );
            unroll_loop_t< ACTION_TYPE, TYPE, n - 1 >::call( destination_ptr + 1, source_ptr + 1 );
        }
    };
    
    //partial specialization template:
    template < typename ACTION_TYPE, typename TYPE >
    struct unroll_loop_t< ACTION_TYPE, TYPE, 1 > {
        INLINE static void call ( TYPE * destination_ptr, TYPE const * source_ptr ) {
            ACTION_TYPE::call( destination_ptr, source_ptr );
        }
    };
    
    //partial specialization template:
    template < typename ACTION_TYPE, typename TYPE >
    struct unroll_loop_t< ACTION_TYPE, TYPE, 0 > {
        INLINE static void call ( TYPE *, TYPE const * ) {
            // nothing
        }
    };
    
    //primary template:
    template < typename ACTION_TYPE, typename TYPE, size_t n >
    struct loop_t {
        INLINE static void call ( TYPE * destination, TYPE const * source ) {
            size_t const block_size = 512; // max number of iterations unrolled
            size_t const number_of_blocks = ( n / block_size ); // integer division
            size_t const partial_block_size = ( n % block_size );
            for ( size_t block = 0; block < number_of_blocks; ++block )
                unroll_loop_t< ACTION_TYPE, TYPE, block_size >::call(
                    &destination[ block * block_size ],
                    &source[ block * block_size ]
                );
            unroll_loop_t< ACTION_TYPE, TYPE, partial_block_size >::call(
                &destination[ number_of_blocks * block_size ],
                &source[ number_of_blocks * block_size ]
            );
        }
    };
    
    template < typename TYPE >
    struct assignment_t {
        INLINE static void call ( TYPE * destination_ptr, TYPE const * source_ptr ) {
            *destination_ptr = *source_ptr;
        }
    };
    
    //convenience function template:
    template < size_t n, typename TYPE >
    INLINE void assign( TYPE * destination, TYPE const * source ) {
        loop_t< assignment_t< TYPE >, TYPE, n >::call( destination, source );
    }
    
    //=========================================================
    
    void zeroize ( double *, size_t const );
    void capture ( double *, size_t const );
    void print ( char const *, double const *, size_t const );
    void print_is_equal ( char const *, double const *, double const *, size_t const );
    void process ( double *, size_t const );
    
    int main () {
        size_t const width = 640; // assume this comes in a .h file
        size_t const height = 480; // assume this comes in a .h file
        size_t const depth = 3; // assume this comes in a .h file
        size_t const size = width * height * depth; // assume this comes in a .h file
    
        double * image_buffer = new double[ size ];
        double * image_1 = new double[ size ];
        double * image_2 = new double[ size ];
    
        capture( image_buffer, size );
    
        print( "image_buffer", image_buffer, size );
        print( "image_1", image_1, size );
        print( "image_2", image_2, size );
    
        cout << endl;
        cout << "assign< size >( image_1, image_buffer );" << endl;
        cout << "assign< size >( image_2, image_buffer );" << endl;
        cout << endl;
    
        assign< size >( image_1, image_buffer );
        assign< size >( image_2, image_buffer );
        
        print( "image_buffer", image_buffer, size );
        print( "image_1", image_1, size );
        print( "image_2", image_2, size );
    
        cout << endl;
    
        print_is_equal( "image_1 == image_buffer", image_1, image_buffer, size );
        print_is_equal( "image_2 == image_buffer", image_2, image_buffer, size );
        print_is_equal( "image_1 == image_2", image_1, image_2, size );
    
        process( image_1, size );
        process( image_2, size );
    
        delete[] image_2;
        delete[] image_1;
        delete[] image_buffer;
        
        return 0;
    }
    
    void zeroize ( double * img, size_t const n ) {
        for ( size_t i = 0; i < n; ++i )
            img[ i ] = 0;
    }
    
    void capture ( double * img, size_t const n ) {
        // simulate capturing an image
        for ( size_t i = 0; i < n; ++i )
            img[ i ] = i + 1;
    }
    
    void print ( char const * name, double const * img, size_t const n ) {
        cout << name << ": [ ";
        size_t const max_length = 2;
        size_t const length = ( n <= max_length ? n : max_length );
        for ( size_t i = 0; i < length; ++i )
            cout << ( i == 0 ? "" : ", " ) << img[ i ];
        if ( length < n )
            cout << ", " << ( length + 1 == n ? "" : "..., " ) << img[ n - 1 ];
        cout << " ]" << endl;
    }
    
    void print_is_equal ( char const * str, double const * img_1, double const * img_2, size_t const n ) {
        bool is_equal = true;
        for ( size_t i = 0; i < n; ++i ) {
            if ( img_1[ i ] != img_2[ i ] ) {
                is_equal = false;
                break;
            }
        }
        cout << str << ": " << is_equal << endl;
    }
    
    void process ( double *, size_t const ) {
        // apply filters
    }
    
    This code can be compiled in g++ 4.5.2 using the following command line (assuming the code is in a file named main.cpp):
    g++ -o main.exe main.cpp -std=c++0x -O3 -Wall -Wextra -Werror
    or compiled in VS2010 using Warning Level 4.  For VS2010, it takes about two minutes to compile in Release mode if you are also producing the Assembly with Source Code ( /FAs ... or Properties / Configuration Properties / C/C++ / Output Files / Assembler Output ) as well.  This code produces the following output:
    image_buffer: [ 1, 2, ..., 921600 ]
    image_1: [ 0, 0, ..., 0 ]
    image_2: [ 0, 0, ..., 0 ]
    
    assign< size >( image_1, image_buffer );
    assign< size >( image_2, image_buffer );
    
    image_buffer: [ 1, 2, ..., 921600 ]
    image_1: [ 1, 2, ..., 921600 ]
    image_2: [ 1, 2, ..., 921600 ]
    
    image_1 == image_buffer: 1
    image_2 == image_buffer: 1
    image_1 == image_2: 1

    Thanks In Advance,
    Joshua Burkholder

  • C9 Lectures: Stephan T. Lavavej - Standard Template Library (STL), 10 of 10

    @devcodex:That's a whole lot of specific code for a very simple and general idea.  I'm not really sure that a destructive endian swap is the way to go; however, try this code out:

    typedef unsigned int SIZE;
    typedef unsigned char BYTE;
    
    template < typename T >
    inline T & swap_endian ( T & t ) {
        static_assert( std::is_integral< T >::value, "swap_endian<T> requires T to be an integral type." );
        SIZE const number_of_bytes = sizeof( t );
        SIZE const middle = number_of_bytes / 2; // integer division
        BYTE * bytes = reinterpret_cast< BYTE * >( &t );
        for ( SIZE i = 0, j = number_of_bytes - 1; i < middle; ++i, --j ) {
            bytes[ i ] ^= bytes[ j ];
            bytes[ j ] ^= bytes[ i ];
            bytes[ i ] ^= bytes[ j ];
        }
        return t;
    }
    Two of these swap_endian's in a row gets you back where you started from ... without having to use temporaries ... ; however, this code can easily be modified to be non-destructive and use the more traditional buffer.  Does this code meet your needs?

    The code above can be used in the following manner:

    #include <iostream>
    #include <iomanip>
    #include <type_traits>
    
    typedef unsigned int SIZE;
    typedef unsigned char BYTE;
    
    template < typename T >
    void print_byte_info ( T const & t ) {
        std::ostream & os = std::cout;
        SIZE const number_of_bytes = sizeof( t );
        SIZE const number_of_bits = 8;
        SIZE const width = 4;
        BYTE const * bytes = reinterpret_cast< BYTE const * >( &t );
        for ( SIZE i = 0, j; i < number_of_bytes; ++i ) {
            os << "byte ( " << std::setw( width ) << ( i + 1 ) << " ): ( address: "
                << std::setw( width ) << static_cast< void const * >( &bytes[ i ] )
                << ", value: " << std::setw( width ) << 
                static_cast< unsigned int >( bytes[ i ] ) << ", binary value: ";
            j = number_of_bits;
            do {
                --j;
                os << ( bytes[ i ] & ( 1 << j ) ? '1' : '0' );
            } while ( j > 0 );
            os << " )\n";
        }
        os << std::endl;
    }
    
    template < typename T >
    inline T & swap_endian ( T & t ) {
        static_assert( std::is_integral< T >::value, "swap_endian<T> requires T to be an integral type." );
        SIZE const number_of_bytes = sizeof( t );
        SIZE const middle = number_of_bytes / 2; // integer division
        BYTE * bytes = reinterpret_cast< BYTE * >( &t );
        for ( SIZE i = 0, j = number_of_bytes - 1; i < middle; ++i, --j ) {
            bytes[ i ] ^= bytes[ j ];
            bytes[ j ] ^= bytes[ i ];
            bytes[ i ] ^= bytes[ j ];
        }
        return t;
    }
    
    int main () {
        unsigned long long x = 0x0102030405060708ULL;
        std::cout << "x ( unsigned long long ): " << x << std::endl;
        std::cout << "x ( unsigned long long | hex ): " << std::hex << x << std::endl;
        std::cout << std::dec;
        print_byte_info( x );
        swap_endian( x );
        std::cout << "swapped x ( unsigned long long ): " << x << std::endl;
        std::cout << "swapped x ( unsigned long long | hex ): " << std::hex << x << std::endl;
        std::cout << std::dec;
        print_byte_info( x );
    
        signed long long y = 0xF7F8F9FAFBFCFDFELL;
        std::cout << "y ( signed long long ): " << y << std::endl;
        std::cout << "y ( signed long long | hex ): " << std::hex << y << std::endl;
        std::cout << std::dec;
        print_byte_info( y );
        swap_endian( y );
        std::cout << "swapped y ( signed long long ): " << y << std::endl;
        std::cout << "swapped y ( signed long long | hex ): " << std::hex << y << std::endl;
        std::cout << std::dec;
        print_byte_info( y );
        
        return 0;
    }
    
    This code will compile using Warning Level 4 in VS2010 or in g++ 4.5.2 using the following command ( assuming the code is in main.cpp ):
    g++ -o main.exe main.cpp -std=c++0x -O3 -Wall -Wextra -Werror
    Here's an example of the output from this code:
    x ( unsigned long long ): 72623859790382856
    x ( unsigned long long | hex ): 102030405060708
    byte (    1 ): ( address: 0044F89C, value:    8, binary value: 00001000 )
    byte (    2 ): ( address: 0044F89D, value:    7, binary value: 00000111 )
    byte (    3 ): ( address: 0044F89E, value:    6, binary value: 00000110 )
    byte (    4 ): ( address: 0044F89F, value:    5, binary value: 00000101 )
    byte (    5 ): ( address: 0044F8A0, value:    4, binary value: 00000100 )
    byte (    6 ): ( address: 0044F8A1, value:    3, binary value: 00000011 )
    byte (    7 ): ( address: 0044F8A2, value:    2, binary value: 00000010 )
    byte (    8 ): ( address: 0044F8A3, value:    1, binary value: 00000001 )
    
    swapped x ( unsigned long long ): 578437695752307201
    swapped x ( unsigned long long | hex ): 807060504030201
    byte (    1 ): ( address: 0044F89C, value:    1, binary value: 00000001 )
    byte (    2 ): ( address: 0044F89D, value:    2, binary value: 00000010 )
    byte (    3 ): ( address: 0044F89E, value:    3, binary value: 00000011 )
    byte (    4 ): ( address: 0044F89F, value:    4, binary value: 00000100 )
    byte (    5 ): ( address: 0044F8A0, value:    5, binary value: 00000101 )
    byte (    6 ): ( address: 0044F8A1, value:    6, binary value: 00000110 )
    byte (    7 ): ( address: 0044F8A2, value:    7, binary value: 00000111 )
    byte (    8 ): ( address: 0044F8A3, value:    8, binary value: 00001000 )
    
    y ( signed long long ): -578437695752307202
    y ( signed long long | hex ): f7f8f9fafbfcfdfe
    byte (    1 ): ( address: 0044F88C, value:  254, binary value: 11111110 )
    byte (    2 ): ( address: 0044F88D, value:  253, binary value: 11111101 )
    byte (    3 ): ( address: 0044F88E, value:  252, binary value: 11111100 )
    byte (    4 ): ( address: 0044F88F, value:  251, binary value: 11111011 )
    byte (    5 ): ( address: 0044F890, value:  250, binary value: 11111010 )
    byte (    6 ): ( address: 0044F891, value:  249, binary value: 11111001 )
    byte (    7 ): ( address: 0044F892, value:  248, binary value: 11111000 )
    byte (    8 ): ( address: 0044F893, value:  247, binary value: 11110111 )
    
    swapped y ( signed long long ): -72623859790382857
    swapped y ( signed long long | hex ): fefdfcfbfaf9f8f7
    byte (    1 ): ( address: 0044F88C, value:  247, binary value: 11110111 )
    byte (    2 ): ( address: 0044F88D, value:  248, binary value: 11111000 )
    byte (    3 ): ( address: 0044F88E, value:  249, binary value: 11111001 )
    byte (    4 ): ( address: 0044F88F, value:  250, binary value: 11111010 )
    byte (    5 ): ( address: 0044F890, value:  251, binary value: 11111011 )
    byte (    6 ): ( address: 0044F891, value:  252, binary value: 11111100 )
    byte (    7 ): ( address: 0044F892, value:  253, binary value: 11111101 )
    byte (    8 ): ( address: 0044F893, value:  254, binary value: 11111110 )

    Hope This Helps,
    Joshua Burkholder

  • CES 2011: Kinect and Live Mesh

    If I'm logged into my Kinect-enabled XBox 360, I can initiate a video call with someone using Windows Live Messenger 2011 on a PC ... and they can accept that video call.  However, ...

    ... How does someone using Windows Live Messenger 2011 on a PC initiate a video call with me that I can actually accept when I'm logged into my Kinect-enabled XBox 360?  When I try this scenario, I see a prompt at the bottom of my XBox 360 screen that someone wants to video chat, but I don't see a way to switch over to Video Kinect and accept the video call.  What am I missing?

    Thanks In Advance For Any Help,
    Joshua Burkholder

  • C9 Lectures: Stephan T. Lavavej - Standard Template Library (STL), 10 of 10

    @Philhippus:Yes, Stephan has only scratched the surface of template metaprogramming (i.e. using C++ templates to create/modify C++ code at compile-time).  Here are a few good references that go into greater detail:

    These books are outstanding ... esp. C++ Templates - The Complete Guide.  Alexandrescu's book is about more than just template metaprogramming ... however, it applies template metaprogramming throughout the text and is an excellent book for showing what can be done with template metaprogramming.  Ensure that you look at the correction to Typelists (i.e. use templates, not #defines, to create lists of types) that Alexandrescu made here: http://www.drdobbs.com/cpp/184403813

    NOTE:  There is also a horribly written book called "C++ Template Metaprogramming - Concepts, Tools, and Techniques from Boost and Beyond".  If you can get through this book ... with its coverage of template metaprogramming for seemingly template metaprogramming's sake and its occasional lack of structure & direction, then you will pick up some template metaprogramming techniques ... and (most importantly) be introduced to the template metaprogramming library called MPL from boost.org:  http://www.boost.org/doc/libs/1_45_0/libs/mpl/doc/index.html  . However, the documentation for Boost's MPL is about as good as the book, so I would go to the documentation first ( http://www.boost.org/doc/libs/1_45_0/libs/mpl/doc/tutorial/tutorial_toc.html  ) ... and then take a look at that book at a library or a bookstore (rather than wasting your money on it ... like I did).

    Hope This Helps,
    Joshua Burkholder

  • C9 Lectures: Stephan T. Lavavej - Standard Template Library (STL), 10 of 10

    @Gordon: MinGW (Minimalist GNU for Windows) can provide gcc and g++ for use off of a portable device (i.e. usb thumb-drive).  Additionally, MinGW ... and MSYS (the MinGW Shell) ... can be "installed" with non-admin rights ... the MinGW installer just needs a folder with no spaces in its path to which it will download all the relevent files and subfolders.

    Previous MinGW installers were worthless; however, the current MinGW installer is outstanding (in comparison).  MinGW can be downloaded here:  http://sourceforge.net/projects/mingw/

    At the time that I'm writing this, "mingw-get-inst-20101030.exe" is the current installer and that installer downloads and installs gcc and g++ version 4.5.0.  The installer can also be used to install MSYS, so ensure that you also install the MSYS Basic System ... this will give you a shell that includes make for makefiles and a number of other utilities.

    Here are step-by-step screen captures of what you should see during the install process:  http://www.joshuaburkholder.com/glut/step_1/

    After the install is complete, just copy and paste the MinGW folder to your portable device ... and ensure that there are no spaces in MinGW's new path.  For ease of access to MSYS ... and therefore to the versions of gcc and g++ in MinGW, create a link to "C:\MinGW\msys\1.0\msys.bat" (or the msys.bat file wherever you installed MinGW) and change the link's "Start in:" path to "C:\MinGW\msys\1.0\bin" (or similar).

    Hope This Helps,
    Joshua Burkholder

    NOTE:  By default, executables built with MinGW's g++ dynamically link to the following DLLs: "C:\MinGW\bin\libgcc_s_dw2-1.dll" and "C:\MinGW\bin\libstdc++-6.dll" ... hence, you should use the

    -enable-auto-import
    flag with g++ when building executables in this default setting.  The current installer does not pollute your PATH environment variable, so you may want to add C:\MinGW\bin (or similar) to your System or User PATH environment variable so that your g++ produced EXEs can find those DLLs ... esp. if you are going to launch those EXEs by double-clicking on them.  MSYS temporarily prepends C:\MinGW\msys\1.0\local\bin (if it exists), C:\MinGW\bin, and C:\MinGW\msys\1.0\bin to the PATH environment variable ... so if you run your EXEs from MSYS, your executables will find the needed DLLs.  Or, you can make copies of these two DLLs and place them next to your EXE.  Alternatively, you can just statically link those libraries to your EXE by using the
    -static
    flag with g++ ... which adds about 1 MB to your executable ... and allows double-click execution of your EXE without having to pollute your PATH environment variable or without having to place DLLs next to your EXE.

    NOTE:  To change the /mingw alias from C:\MinGW to whatever the portable device path is, edit C:\MinGW\msys\1.0\etc\fstab.

  • C9 Lectures: Stephan T. Lavavej - Standard Template Library (STL), 9 of n

    @STL:Thanks for the heads up on not taking the address of Standard Library member functions.  Where is that detailed in the standard?

    Thanks In Advance,
    Joshua Burkholder

  • C9 Lectures: Stephan T. Lavavej - Standard Template Library (STL), 9 of n

    @NotFredSafe:

    This is __not__ a compiler bug in either GNU/g++ or Visual Studio.

    Your code assumes that type U directly has member functions begin() const and end() const, vice inheriting them.  Your code also assumes that const_iterator comes directly from U, vice inheriting it.  The C++ standard does __not__ assume this for associative containers like std::map and std::set (see section 23.6.1 point 2 [for std::map] and section 23.6.3 point 2 [for std::set] of the current draft of the C++ standard).  According to the C++ standard, implementers are free to typedef std::map<...>::const_iterator or std::set<...>::const_iterator any way they want to ... so since Dinkumware uses inheritance to implement std::map and std::set, then Dinkumware can choose to just use the inherited std::_Tree<...>::const_iterator std::_Tree<...>::begin() const and std::_Tree<...>::const_iterator std::_Tree<...>::end () const.  Visual Sudio uses Dinkumware's STL implementation ... while GNU/g++ does not.  Dinkumware's std::map and std::set implementation uses inheritance ... while GNU/g++ does not.  If GNU/g++ used this inherited structure, then the results from GNU/g++ and Visual Studio would be the same.  Here's an example:

    #include <iostream>
    #include <vector>
    #include <list>
    #include <set>
    #include <map>
    
    template <typename T>
    struct is_container {
        template <
            typename U,
            typename U::const_iterator (U::*)() const,
            typename U::const_iterator (U::*)() const
        >
        struct sfinae {};
        
        template < typename U >
        static char test ( sfinae< U, &U::begin, &U::end >* );
    
        template < typename U >
        static long test ( ... );
        
        enum {
            value = ( sizeof( test< T >( 0 ) ) == 1 )
        };
    };
    
    template < typename T >
    struct ContainerInheritedFrom {
        typedef T const * const_iterator;
        const_iterator begin() const {
            return const_iterator();
        }
        const_iterator end() const {
            return const_iterator();
        }
    };
    
    template < typename T >
    struct ContainerThatInherits : public ContainerInheritedFrom< T > {
        //
    };
    
    int main () {
        std::cout << is_container<std::vector<std::string> >::value << ' ';
        std::cout << is_container<std::list<std::string> >::value << ' ';
        std::cout << is_container<std::set<std::string> >::value << ' ';
        std::cout << is_container<std::map<std::string, std::string> >::value << '\n';
    
        
        ContainerInheritedFrom< std::string > cif;
        ContainerInheritedFrom< std::string >::const_iterator cif_ci = cif.begin();
        cif_ci = cif.end();
    
        ContainerThatInherits< std::string > cti;
        ContainerThatInherits< std::string >::const_iterator cti_ci = cti.begin();
        cti_ci = cti.end();
    
        std::cout << is_container< ContainerInheritedFrom< std::string > >::value << ' ';
        std::cout << is_container< ContainerThatInherits< std::string > >::value << '\n';
    } 
    
    GNU/g++ Version 4.5.0:
    g++ main.cpp -W -Wall -o main.exe
    ./main.exe
    1 1 1 1
    1 0
    Visual Studio 2010:
    1 1 0 0
    1 0

    Because your code requires something that the C++ standard does not require, your code is not a good way to check for a container at compile time ... and is implementation dependent.  You should change your code to reflect the C++ standard requirements.

    Also, good info on Substitution Failure Is Not An Error (SFINAE) can be found on page 106 of C++ Templates: The Complete Guide by Vandevoorde and Josuttis.

    Hope This Clarifies,
    Joshua Burkholder

     P.S. - If you wanted to keep your previous structure and still be able to pick up the associative containers, std::set and std::map, then you could always use a partial specialization on your is_container<...> struct.  Here's an example:

    #include <iostream>
    #include <vector>
    #include <list>
    #include <set>
    #include <map>
    
    template < typename T1, typename T2 >
    struct is_same {
        static bool const value = false;
    };
    
    template < typename T1 >
    struct is_same < T1, T1 > {
        static bool const value = true;
    };
    
    template <typename T>
    struct is_container {
    
        template <
            typename U,
            typename U::const_iterator (U::*)() const,
            typename U::const_iterator (U::*)() const
        >
        struct sfinae {};
        
        template < typename U >
        static char test ( sfinae< U, &U::begin, &U::end >* );
        
        template < typename U >
        static long test ( ... );
        
        static bool const value = ( sizeof( test< T >( 0 ) ) == 1 );
    };
    
    template <
        template < typename, typename, typename > class S, /* Set */
        typename K, /* Key */
        typename C, /* Compare */
        typename A  /* Allocator */
    >
    struct is_container < S< K, C, A > > {
        static bool const value = (
            is_same< S< K, C, A >, std::set< K, C, A > >::value
            ||
            is_same< S< K, C, A >, std::multiset< K, C, A > >::value
        );
    };
    
    template <
        template < typename, typename, typename, typename > class M, /* Map */
        typename K, /* Key */
        typename T, /* T */
        typename C, /* Compare */
        typename A  /* Allocator */
    >
    struct is_container < M< K, T, C, A > > {
        static bool const value = (
            is_same< M< K, T, C, A >, std::map< K, T, C, A > >::value
            ||
            is_same< M< K, T, C, A >, std::multimap< K, T, C, A > >::value
        );
    };
    
    template < typename T >
    struct ContainerInheritedFrom {
        typedef T const * const_iterator;
        const_iterator begin() const {
            return const_iterator();
        }
        const_iterator end() const {
            return const_iterator();
        }
        
    };
    
    template < typename T >
    struct ContainerThatInherits : public ContainerInheritedFrom< T > {
        //
    };
    
    int main () {
        std::cout << is_container<std::vector<std::string> >::value << ' ';
        std::cout << is_container<std::list<std::string> >::value << ' ';
        std::cout << is_container<std::set<std::string> >::value << ' ';
        std::cout << is_container<std::map<std::string, std::string> >::value << '\n';
    
        
        ContainerInheritedFrom< std::string > cif;
        ContainerInheritedFrom< std::string >::const_iterator cif_ci = cif.begin();
        cif_ci = cif.end();
    
        ContainerThatInherits< std::string > cti;
        ContainerThatInherits< std::string >::const_iterator cti_ci = cti.begin();
        cti_ci = cti.end();
    
        std::cout << is_container< ContainerInheritedFrom< std::string > >::value << ' ';
        std::cout << is_container< ContainerThatInherits< std::string > >::value << '\n';
        
    } 
    
    Of course, this is a kludge (so you don't have to dramatically modify your code) and is not recommended ... but it works. Wink

    Based on the kludge above, GNU/g++ Version 4.5.0 outputs:

    g++ main.cpp -W -Wall -o main.exe
    ./main.exe
    1 1 1 1
    1 0
    Based on the kludge above, Visual Studio 2010 outputs:
    1 1 1 1
    1 0

     

  • C9 Lectures: Stephan T. Lavavej - Standard Template Library (STL), 9 of n

    @Burkholder:Disregard my no-compiler-warning for C++ in Visual Studio 2010.  I was compiling with Warning Level Level3, vice Warning Level Level4.  Once I switched to Level4, I received the following warning

    warning C4238: nonstandard extension used : class rvalue used as lvalue
    Still no compiler error though, but at least this is the same behavior as g++.

     

    Joshua Burkholder