Last active
September 10, 2019 11:38
-
-
Save tristan0x/5bd947e8d89a187a6cbf8747b05c3ea3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This gist intends to provide an helper function to create | |
// std::initializer_list of a certain size with a fixed value. | |
// 2 implementations are available: | |
// | |
// 1. the `constant_int`: only support integer values | |
// 2. the `constant`: support any kind of value | |
// | |
// This piece of code requires C++17 standard | |
// use-case: | |
// | |
// You have a class whose constructor accepts an std::initializer_list | |
// | |
// struct MyVector { | |
// template <typename T> | |
// MyVector(std::initializer_list<T>); | |
// // [...] | |
// }; | |
// | |
// | |
// Now, you want to create an instance of this container | |
// by giving an std::initializer_list of a variadic size | |
// (known at compile time) with a fixed value: | |
// template <std::size_t N, typename T> | |
// MyVector create(T value) { | |
// return { constant<N>(value) }; | |
// } | |
// | |
// auto pi3 = create<3>(3.14); // { 3.14, 3.14, 3.14 } | |
// auto pi3 = create<4>(3.14); // { 3.14, 3.14, 3.14, 3.14 } | |
// | |
// Now the purpose of this gist is to provide an implementation | |
// of this `constant` function | |
#include <initializer_list> | |
#include <utility> | |
template <std::size_t N, typename T, T Value, T... Accu> | |
auto constant_int_impl() { | |
if constexpr (N <= 0) { | |
return std::integer_sequence<T, Accu...>(); | |
} else { | |
return constant_int_impl<N - 1, T, Value, Value, Accu...>(); | |
} | |
} | |
template <std::size_t N, typename T, T Value> | |
using constant_int_t = std::decay_t<decltype(constant_int_impl<N, T, Value>())>; | |
template <typename T, T... Values> | |
std::initializer_list<T> | |
to_initializer_list(std::integer_sequence<T, Values...>) { | |
return {Values...}; | |
} | |
/** | |
* \brief Construct an initializer list of size \a N with all fields set to \a | |
* Value Example: | |
* std::initializer_list<double> il(constant_int<3, int, 42>()); | |
* // il == { 42, 42, 42 } | |
* | |
* Because the value is passed as template parameter, and because C++ doesn't | |
* support float-point types for non-type template parameter, this function only | |
* supports integers. | |
*/ | |
template <std::size_t N, typename T, T Value> | |
std::initializer_list<T> constant_int() { | |
return to_initializer_list(constant_int_t<N, T, Value>()); | |
} | |
/** | |
* generate a std::integer_sequence of size N with value Value (default 1) | |
*/ | |
template <std::size_t N, typename Int = int, Int Value = 1, Int... Accu> | |
constexpr auto ones() { | |
if constexpr (N == 0) { | |
return std::integer_sequence<Int, Accu...>(); | |
} else { | |
return ones<N - 1, Int, Value, Value, Accu...>(); | |
} | |
} | |
template <typename T, typename Int, Int... Ones> | |
std::initializer_list<T> constant_impl(T value, | |
std::integer_sequence<Int, Ones...>) { | |
static const std::initializer_list<T> result{(Ones, value)...}; | |
return result; | |
} | |
/** | |
* Same purpose than \a constant_int but accepts | |
* any kind of type for value. | |
*/ | |
template <std::size_t N, typename T> | |
constexpr std::initializer_list<T> constant(T value) { | |
return constant_impl(value, ones<N>()); | |
} | |
// ---- | |
#include <iostream> | |
#include <iterator> | |
#include <vector> | |
int main() { | |
{ | |
// test to_initializer_list | |
std::vector<int> v( | |
to_initializer_list(std::integer_sequence<int, 1, 2, 3>())); | |
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::clog, " ")); | |
std::clog << '\n'; | |
// 1 2 3 | |
} | |
{ | |
// test constant_int with integer | |
std::vector<int> v(constant_int<3, int, 42>()); | |
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::clog, " ")); | |
std::clog << '\n'; | |
// 42 42 42 | |
} | |
{ | |
// test constant_int with double | |
std::vector<float> v(constant<3>(3.14f)); | |
std::copy(v.begin(), v.end(), | |
std::ostream_iterator<decltype(v)::value_type>(std::clog, " ")); | |
std::clog << '\n'; | |
// 3.14 3.14 3.14 | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment