std:: adjacent_difference
|
Definido en el encabezado
<numeric>
|
||
|
template
<
class
InputIt,
class
OutputIt
>
OutputIt adjacent_difference
(
InputIt first, InputIt last,
|
(1) | (constexpr desde C++20) |
|
template
<
class
ExecutionPolicy,
class
ForwardIt1,
class
ForwardIt2
>
|
(2) | (desde C++17) |
|
template
<
class
InputIt,
class
OutputIt,
class
BinaryOp
>
OutputIt adjacent_difference
(
InputIt first, InputIt last,
|
(3) | (constexpr desde C++20) |
|
template
<
class
ExecutionPolicy,
class
ForwardIt1,
class
ForwardIt2,
class
BinaryOp
>
|
(4) | (desde C++17) |
Sea
T
el tipo de valor de
decltype
(
first
)
.
[
first
,
last
)
está vacío, no hace nada.
-
Crea un acumulador
acc
de tipo
T, y lo inicializa con * first . - Asigna acc a * d_first .
-
Para cada iterador
iter
en
[++ first,last)en orden, realiza las siguientes operaciones en orden:
T
, y lo inicializa con
*
iter
.
[
first
,
last
)
está vacío, no hace nada.
- Asigna * first a * d_first .
-
Para cada entero
i
en
[1,std:: distance ( first, last )), realiza las siguientes operaciones en orden:
Dado binary_op como la operación binaria real:
- Si se satisface cualquiera de las siguientes condiciones, el programa está mal formado:
-
- Para las sobrecargas (1,3) :
-
-
Tno es construible desde * first . - acc no es escribible a d_first .
- El resultado de binary_op ( val, acc ) (hasta C++20) binary_op ( val, std :: move ( acc ) ) (desde C++20) no es escribible a d_first .
-
- Para las sobrecargas (2,4) :
-
- * first no es escribible a d_first .
- El resultado de binary_op ( * first, * first ) no es escribible a d_first .
- Dado d_last como el iterador a ser devuelto , si alguna de las siguientes condiciones se satisface, el comportamiento es indefinido:
|
(desde C++20) |
-
-
Para las sobrecargas
(2,4)
,
[first,last)y[d_first,d_last)se superponen. -
binary_op
modifica cualquier elemento de
[first,last)o[d_first,d_last). -
binary_op
invalida cualquier iterador o subrango en
[first,last]o[d_first,d_last].
-
Para las sobrecargas
(2,4)
,
Contenidos |
Parámetros
| first, last | - | el par de iteradores que definen el rango de elementos a |
| d_first | - | el inicio del rango de destino |
| policy | - | la política de ejecución a utilizar |
| op | - |
objeto función de operación binaria que será aplicado.
La firma de la función debe ser equivalente a la siguiente: Ret fun ( const Type1 & a, const Type2 & b ) ;
La firma no necesita tener
const
&
.
|
| Requisitos de tipo | ||
-
InputIt
debe cumplir con los requisitos de
LegacyInputIterator
.
|
||
-
OutputIt
debe cumplir con los requisitos de
LegacyOutputIterator
.
|
||
-
ForwardIt1, ForwardIt2
debe cumplir con los requisitos de
LegacyForwardIterator
.
|
||
Valor de retorno
Iterador al elemento después del último elemento escrito, o
d_first
si
[
first
,
last
)
está vacío.
Complejidad
Dado N como std:: distance ( first, last ) :
Excepciones
Las sobrecargas con un parámetro de plantilla llamado
ExecutionPolicy
reportan errores de la siguiente manera:
-
Si la ejecución de una función invocada como parte del algoritmo lanza una excepción y
ExecutionPolicyes uno de los standard policies , std::terminate es llamado. Para cualquier otroExecutionPolicy, el comportamiento está definido por la implementación. - Si el algoritmo falla al asignar memoria, std::bad_alloc es lanzado.
Implementación posible
| adjacent_difference (1) |
|---|
template<class InputIt, class OutputIt> constexpr // since C++20 OutputIt adjacent_difference(InputIt first, InputIt last, OutputIt d_first) { if (first == last) return d_first; typedef typename std::iterator_traits<InputIt>::value_type value_t; value_t acc = *first; *d_first = acc; while (++first != last) { value_t val = *first; *++d_first = val - std::move(acc); // std::move since C++20 acc = std::move(val); } return ++d_first; } |
| adjacent_difference (3) |
template<class InputIt, class OutputIt, class BinaryOp> constexpr // since C++20 OutputIt adjacent_difference(InputIt first, InputIt last, OutputIt d_first, BinaryOp op) { if (first == last) return d_first; typedef typename std::iterator_traits<InputIt>::value_type value_t; value_t acc = *first; *d_first = acc; while (++first != last) { value_t val = *first; *++d_first = op(val, std::move(acc)); // std::move since C++20 acc = std::move(val); } return ++d_first; } |
Notas
acc se introdujo debido a la resolución de LWG issue 539 . La razón de usar acc en lugar de calcular directamente las diferencias es porque la semántica de este último es confusa si los siguientes tipos no coinciden:
-
el tipo de valor de
InputIt -
el(los) tipo(s) escribible(s) de
OutputIt - los tipos de los parámetros de operator - o op
- el tipo de retorno de operator - o op
acc sirve como el objeto intermedio para almacenar en caché los valores de los elementos iterados:
-
su tipo es el tipo de valor de
InputIt - el valor escrito en d_first (que es el valor de retorno de operator - o op ) se le asigna
- su valor se pasa a operator - o op
char i_array[4] = {100, 100, 100, 100}; int o_array[4]; // OK: realiza conversiones cuando es necesario // 1. crea "acc" de tipo char (el tipo de valor) // 2. "acc" se asigna al primer elemento de "o_array" // 3. los argumentos char se usan para multiplicación larga (char -> long) // 4. el producto long se asigna al rango de salida (long -> int) // 5. el siguiente valor de "i_array" se asigna a "acc" // 6. vuelve al paso 3 para procesar los elementos restantes en el rango de entrada std::adjacent_difference(i_array, i_array + 4, o_array, std::multiplies<long>{});
Ejemplo
#include <array> #include <functional> #include <iostream> #include <iterator> #include <numeric> #include <vector> void println(auto comment, const auto& sequence) { std::cout << comment; for (const auto& n : sequence) std::cout << n << ' '; std::cout << '\n'; }; int main() { // Implementación por defecto - la diferencia entre dos elementos adyacentes std::vector v{4, 6, 9, 13, 18, 19, 19, 15, 10}; println("Inicialmente, v = ", v); std::adjacent_difference(v.begin(), v.end(), v.begin()); println("v modificado = ", v); // Fibonacci std::array<int, 10> a {1}; std::adjacent_difference(std::begin(a), std::prev(std::end(a)), std::next(std::begin(a)), std::plus<>{}); println("Fibonacci, a = ", a); }
Salida:
Inicialmente, v = 4 6 9 13 18 19 19 15 10 v modificado = 4 2 3 4 5 1 0 -4 -5 Fibonacci, a = 1 1 2 3 5 8 13 21 34 55
Informes de defectos
Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares de C++ publicados anteriormente.
| DR | Aplicado a | Comportamiento publicado | Comportamiento correcto |
|---|---|---|---|
| LWG 242 | C++98 | op no podía tener efectos secundarios |
no puede modificar
los rangos involucrados |
| LWG 539 | C++98 |
faltaban los requisitos de tipo necesarios para que las
evaluaciones de resultados y asignaciones fueran válidas |
añadidos |
| LWG 3058 | C++17 |
para las sobrecargas
(2,4)
, el resultado de cada invocación
de operator - o op se asignaba a un objeto temporal, y ese objeto se asigna al rango de salida |
asignar los resultados
directamente al rango de salida |
Véase también
|
calcula la suma parcial de un rango de elementos
(plantilla de función) |
|
|
suma o pliega un rango de elementos
(plantilla de función) |