Skip to content

Instantly share code, notes, and snippets.

@tristan0x
Last active September 10, 2019 11:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tristan0x/5bd947e8d89a187a6cbf8747b05c3ea3 to your computer and use it in GitHub Desktop.
Save tristan0x/5bd947e8d89a187a6cbf8747b05c3ea3 to your computer and use it in GitHub Desktop.
// 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