The largest issue using Clang with Visual Studio is the standard library. Microsoft's standard library does not use language features that Visual C++ does not support. Also, my experience is that Clang cannot parse many of Microsoft's standard library headers.
Because I wanted to experiment with uniform initialization, and because Microsoft does not include <initializer_list> I decided to implement it myself.
std::initializer_list is a class used by the compiler to implement uniform initialization. std::initializer_list is defined in section 18.9 [support.initlist] of the C++11 standard. 7.1.6.4.6 [dcl.spec.auto] specifies how std::initializer_list and auto interact. 8.5.4 [dcl.init.list] describes list-initialization. 13.3.3.1.5 [over.ics.list] explains how std::initializer_list interacts with function calls, including constructors. 13.3.3.2.3 [over.ics.rank] lists how implicit conversions are ranked when dealing with function overloads. 14.8.2.1.1 [temp.deduct.call] describes how template argument deduction is done with a std::initializer_list as the argument.
Fortunately, std::initializer_list is a pretty simple class. It has the basics necessary for a collection. It has pointers for iterators, which gives it random access iterators. It has begin, end, and size functions. And last of all it has a default iterator. None of these are difficult to implement.
The standard says the following in section 8.5.4.5 [dcl.init.list]:
An object of type std::initializer_list<E> is constructed from an initializer list as if the implementation allocated an array of N elements of type E, where N is the number of elements in the initializer list. Each element of that array is copy-initialized with the corresponding element of the initializer list, and the std::initializer_list<E> object is constructed to refer to that array.8.5.4.6 [dcl.init.list]:
The lifetime of the array is the same as that of the initializer_list object.Somehow an array is allocated an somehow the initializer_list is constructed to refer to this array. In section 18.9.1 [support.initlist] the only constructor that is listed is the default constructor. It eventually occurred to me that the method of getting the array into the initializer_list is implementation dependent.
Clang gives the following error if the layout of initializer_list is not what is expected:
error: cannot compile this weird std::initializer_list yetBy looking up "weird std::initializer_list" in the Clang source code I was able to determine that Clang has the following restrictions on initializer_list:
- There must be at least two member variables.
- The first member variable must be of type const E*.
- The first member variable is a pointer to the beginning of the array.
- The second member variable must either be of type const E* or size_t.
- If the second member variable is a pointer, then it points to one past the end of the array.
- If the second member variable is a size_t, then it is the number of elements in the array.
- All other fields are ignored by Clang.
Notice that Clang does not actually use a constructor to build the initializer_list. It injects the data directly into the structure.
Finally there is enough information to write std::initializer_list. Since it uses size_t it is necessary to also implement part of cstddef.
#ifndef CSTDDEF_H
#define CSTDDEF_H
namespace std {
typedef unsigned int size_t;
}
#endif // CSTDDEF_H
#ifndef INITIALIZER_LIST_H
#define INITIALIZER_LIST_H
#include "cstddef.h"
namespace std {
template<class E> class initializer_list {
const E *_B;
const E *_E;
public:
typedef E value_type;
typedef const E& reference;
typedef const E& const_reference;
typedef size_t size_type;
typedef const E* iterator;
typedef const E* const_iterator;
initializer_list() noexcept : _B(nullptr), _E(nullptr) {}
size_t size() const noexcept { return _E - _B; } // number of elements
const E* begin() const noexcept { return _B; } // first element
const E* end() const noexcept {return _E; } // one past the last element
};
// 18.9.3 initializer list range access
template<class E> const E* begin(initializer_list<E> il) noexcept
{ return il.begin(); }
template<class E> const E* end(initializer_list<E> il) noexcept
{ return il.end(); }
}
#endif // INITIALIZER_LIST_H