Date: Mon, 15 Jul 2019 10:41:28 -0400

On Sat, Jul 13, 2019 at 5:55 PM Jordi Vilar via Std-Proposals <

std-proposals_at_[hidden]> wrote:

>

> Hi all,

>

> I would like to propose a very simple addition to the standard library in

order to simplify variadic parameter pack expansion, and before writing a

formal proposal I just wanted to share it in order to get feedback.

>

> Typically, expanding indices sequences require writing a dedicated helper

wrapper. This is tedious and offers no value at all.

True, but C++2a's "lambdas with template parameters" does provide one

(arcane) way around that issue. I'll show it below.

> The proposal is then:

>

> namespace std {

> template<typename F, typename T, T... indices>

> constexpr decltype(auto) apply(F&& function, [[maybe_unused]]

std::integer_sequence<T, indices...> sequence)

> {

> return function(std::integral_constant<T, indices>{}...);

> }

> }

I think Garrett May is correct that if you wanted to get this end result,

you'd do better to ask for `index_sequence` to be tuple-like.

Alisdair Meredith's P1789

<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1789r0.html>

covers that feature request already. (However, P1789's motivation is based

on "expansion statements," and my impression is that "expansion statements"

are no longer likely to make C++2a. So P1789 is probably unlikely to make

C++2a either. As of right now, P1789 is "P2 Unscheduled" before LEWG at

Cologne this week.)

> This simple helper function could allow us to write, for instance:

>

> /// performs the addition of two arrays of arithmetic types

> template<typename T, std::size_t N>

> auto operator +(const std::array<T, N>& lhs, const std::array<T, N>& rhs)

> -> std::enable_if_t<std::is_arithmetic_v<T>, std::array<T, N>>

> {

> return std::apply([&](auto... indices) { return std::array<T, N>{

(std::get<indices>(lhs) + std::get<indices>(rhs))... }; },

std::make_index_sequence<N>{});

> }

>

> int main(int argc, char** argv)

> {

> auto result = std::array{1, 2, 3} + std::array{5, 4, 3};

> apply([&](auto... indices) { (std::cout << ... << result[indices]);

}, std::make_index_sequence<3>{});

> }

You need to bring *much* better motivating examples. These two can already

be written as

template<class T, std::size_t N> requires std::is_arithmetic_v<T>

std::array<T, N> operator+(const std::array<T, N>& lhs, const std::array<T,

N>& rhs)

{ std::array<T, N> result = lhs;

for (int i = 0; i < N; ++i) {

result[i] = rhs[i];

return result;

}

int main()

{

auto result = std::array{1, 2, 3} + std::array{5, 4, 3};

for (int elt : result) {

std::cout << elt;

}

}

Consider using `MyTuple<Ts...>` instead of `std::array<T, N>`. In that

case, what you'd end up with in C++2a would use the workaround of

lambdas-with-template-parameters and would look like this:

template<Arithmetic... Ts>

MyTuple<Ts...> operator+(const MyTuple<Ts...>& lhs, const MyTuple<Ts...>&

rhs)

{

return [&]<size_t... Is>(std::index_sequence<Is...>) {

return makeMyTuple(std::get<Is>(lhs) + std::get<Is>(rhs) ...);

}(std::make_index_sequence<sizeof...(Ts)>());

}

int main()

{

auto result = makeMyTuple(1, 2, 3) + makeMyTuple(5, 4, 3);

[&]<size_t... Is>(std::index_sequence<Is...>) {

(std::cout << ... << std::get<Is>(result));

}(std::make_index_sequence<3>());

}

HTH,

Arthur

std-proposals_at_[hidden]> wrote:

>

> Hi all,

>

> I would like to propose a very simple addition to the standard library in

order to simplify variadic parameter pack expansion, and before writing a

formal proposal I just wanted to share it in order to get feedback.

>

> Typically, expanding indices sequences require writing a dedicated helper

wrapper. This is tedious and offers no value at all.

True, but C++2a's "lambdas with template parameters" does provide one

(arcane) way around that issue. I'll show it below.

> The proposal is then:

>

> namespace std {

> template<typename F, typename T, T... indices>

> constexpr decltype(auto) apply(F&& function, [[maybe_unused]]

std::integer_sequence<T, indices...> sequence)

> {

> return function(std::integral_constant<T, indices>{}...);

> }

> }

I think Garrett May is correct that if you wanted to get this end result,

you'd do better to ask for `index_sequence` to be tuple-like.

Alisdair Meredith's P1789

<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1789r0.html>

covers that feature request already. (However, P1789's motivation is based

on "expansion statements," and my impression is that "expansion statements"

are no longer likely to make C++2a. So P1789 is probably unlikely to make

C++2a either. As of right now, P1789 is "P2 Unscheduled" before LEWG at

Cologne this week.)

> This simple helper function could allow us to write, for instance:

>

> /// performs the addition of two arrays of arithmetic types

> template<typename T, std::size_t N>

> auto operator +(const std::array<T, N>& lhs, const std::array<T, N>& rhs)

> -> std::enable_if_t<std::is_arithmetic_v<T>, std::array<T, N>>

> {

> return std::apply([&](auto... indices) { return std::array<T, N>{

(std::get<indices>(lhs) + std::get<indices>(rhs))... }; },

std::make_index_sequence<N>{});

> }

>

> int main(int argc, char** argv)

> {

> auto result = std::array{1, 2, 3} + std::array{5, 4, 3};

> apply([&](auto... indices) { (std::cout << ... << result[indices]);

}, std::make_index_sequence<3>{});

> }

You need to bring *much* better motivating examples. These two can already

be written as

template<class T, std::size_t N> requires std::is_arithmetic_v<T>

std::array<T, N> operator+(const std::array<T, N>& lhs, const std::array<T,

N>& rhs)

{ std::array<T, N> result = lhs;

for (int i = 0; i < N; ++i) {

result[i] = rhs[i];

return result;

}

int main()

{

auto result = std::array{1, 2, 3} + std::array{5, 4, 3};

for (int elt : result) {

std::cout << elt;

}

}

Consider using `MyTuple<Ts...>` instead of `std::array<T, N>`. In that

case, what you'd end up with in C++2a would use the workaround of

lambdas-with-template-parameters and would look like this:

template<Arithmetic... Ts>

MyTuple<Ts...> operator+(const MyTuple<Ts...>& lhs, const MyTuple<Ts...>&

rhs)

{

return [&]<size_t... Is>(std::index_sequence<Is...>) {

return makeMyTuple(std::get<Is>(lhs) + std::get<Is>(rhs) ...);

}(std::make_index_sequence<sizeof...(Ts)>());

}

int main()

{

auto result = makeMyTuple(1, 2, 3) + makeMyTuple(5, 4, 3);

[&]<size_t... Is>(std::index_sequence<Is...>) {

(std::cout << ... << std::get<Is>(result));

}(std::make_index_sequence<3>());

}

HTH,

Arthur

Received on 2019-07-15 09:43:35