There is a implementation quite similar to std::initializer_list
used in an environment where standart C++ library is not available:
template<typename T>
class initializer_list {
public:
using value_type = T;
using reference = const T &;
using const_reference = const T &;
using size_type = size_t;
using iterator = const T *;
using const_iterator = const T *;
private:
iterator m_array;
size_type m_length;
constexpr initializer_list( const_iterator array, size_type length ) noexcept : m_array( array ), m_length( length ) {}
public:
constexpr initializer_list( void ) noexcept : m_array( nullptr ), m_length( 0 ) {}
/* Number of elements */
constexpr size_type size( void ) const noexcept {
return m_length;
}
/* First element */
constexpr const_iterator begin( void ) const noexcept {
return m_array;
}
/* One past the last element */
constexpr const_iterator end( void ) const noexcept {
return begin() + size();
}
};
template<typename T>
constexpr const T * begin( initializer_list<T> list ) noexcept {
return list.begin();
}
template<typename T>
constexpr const T * end( initializer_list<T> list ) noexcept {
return list.end();
}
Then such initializer_list<T>
is about to be used in another class constructor:
template<typename T>
struct user {
user( initializer_list<T> init_values ) { ... }
};
and the intension to use both things together:
user<int> sample { 1, 2, 3, 4, 5 };
Obviously, the compiler does not know how to deduce the type of the brace initializer list so that it uses initializer_list as implemented above. I suppose some kind of deduction guide shall be implemented to connect my implementation of initializer_list and the brace initializer list. But I have no clue how to implement such.
Can someone advise me how to implement the described deduction guide?
There is no such thing. While freestanding C++ implementations are free to only implement parts of the standard library, there are some components which all valid C++ implementations must provide.
std::initializer_list
is among these components.As such, if you have a valid C++11 or higher implementation of C++, then you must have the
<initializer_list>
header and its contents. This is not optional. If your implementation doesn't provide one, then it is defective.The reason it is not optional is that the important functionality of
std::initializer_list
(that is, its generation from a braced-init-list) is a function of the C++ language, not of the library. That is, it is impossible for code outside of the compiler to make the{}
grammatical construct become a type that is exactly analogous to howstd::initializer_list
behaves.Consider your code:
If you think about it, this ought to mean that a constructor of
user<int>
will be called that takes 5 parameters. That's what it would mean ifuser
had a constructor of 5 integer parameters, after all. But that's not what you want it to mean, and it wouldn't mean that forvector<int>
. Why?Because C++'s language has a special rule about list initialization that detects the presence of a constructor which takes a
std::initializer_list
that matches the braced-init-list types, and then creates astd::initializer_list
to pass to this constructor. This rule keys off of the presences of a constructor that takesstd::initializer_list
and no other type.Your code does not work, not because of a lack of deduction guides, but because your
initializer_list
type has no special rules as far as the language is concerned.You cannot recreate this language behavior with a user-defined type. Just as you cannot make
typeid
return a type other thanstd::type_info
. Just as you cannot makeenum class byte: unsigned char{};
have the same behavior asstd::byte
.