Reputation: 1010
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?
Upvotes: 0
Views: 669
Reputation: 473407
in an environment where standart C++ library is not available
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 how std::initializer_list
behaves.
Consider your code:
user<int> sample { 1, 2, 3, 4, 5 };
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 if user
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 for vector<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 a std::initializer_list
to pass to this constructor. This rule keys off of the presences of a constructor that takes std::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 than std::type_info
. Just as you cannot make enum class byte: unsigned char{};
have the same behavior as std::byte
.
Upvotes: 4