mikejsavage.co.uk • About • Archive • RSS • Thanks for blocking ads! Blocking ads owns: AdGuard for Safari / uBlock Origin for everything else
Credit for this one to https://nitter.net/Donzanoid/status/1611315409596071936.
C++'s initializer_list is dogshit:
> cat a.cpp
#include <initializer_list>
> cl.exe /std:c++20 a.cpp /P > /dev/null; and wc -l a.i
Microsoft (R) C/C++ Optimizing Compiler Version 19.36.32534 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
a.cpp
8988 a.i
> g++ -E a.cpp -std=c++20 | wc -l
115
> clang++ -E a.cpp -std=c++20 | wc -l
393
There's actually no compiler magic involved here and initializer_list
is pretty much just span
so very simple to implement, but you need a few tricks to get it to actually work:
On that last point you may be wondering why bother with this at all. You can't keep a codebase completely STL-free, be it because of certain things where the non-STL way is extremely painful (e.g. MSVC atomics), or unavoidable third party libraries pulling in STL headers (e.g. metal-cpp). So we need to make this not clash with the real thing.
#if COMPILER_GCC
// GCC refuses to compile if the implementation doesn't exactly match the STL
#include <initializer_list>
#else
#define _INITIALIZER_LIST_ // MSVC
#define _LIBCPP_INITIALIZER_LIST // clang
namespace std {
template< typename T >
class initializer_list {
public:
#if COMPILER_MSVC
constexpr initializer_list( const T * first_, const T * one_after_end_ ) : first( first_ ), one_after_end( one_after_end_ ) { }
#else
constexpr initializer_list( const T * first_, size_t n ) : first( first_ ), one_after_end( first_ + n ) { }
#endif
const T * begin() const { return first; }
const T * end() const { return one_after_end; }
size_t size() const { return one_after_end - first; }
private:
const T * first;
const T * one_after_end;
};
}
#endif
You may also want to add your own header guards against the STL defines, or you can just make sure you always include this first.