Si tengo un objeto a
que o una matriz incorporada o un tipo de clase con un operator []
adecuado, y su tipo devuelto se puede indexar, ¿cómo debería escribir una función genérica que pueda indexarlos todos con una variadic llamada en lugar de bloque de soporte separado? En otras palabras, puedo hacer expresiones como:¿Cómo se puede hacer una función de indexación encadenada basada en variantes?
a[i0][i1]...[iK]
y quiero ser capaz de escribir como una única función:
slice(a, i0, i1, ..., iK)
ya que las reglas de C++ requieren operator []
a trabajar en argumentos individuales , haciéndolo menos compatible con cosas variadas. (Esta pregunta se basa en un hilo de Usenet, donde he intentado preguntar algo similar; terminando la solución sólo posiblemente anidados-matrices incorporadas en mí mismo.)
Un primer intento:
template < typename T, typename U >
constexpr
auto slice(T &&t, U &&u) noexcept(???) -> ???
{ return ce_forward<T>(t)[ ce_forward<U>(u) ]; }
template < typename T, typename U, typename V, typename ...W >
constexpr
auto slice(T &&t, U &&u, V &&v, W... &&w) noexcept(???) -> ???
{
return slice(ce_forward<T>(t)[ce_forward<U>(u)], ce_forward<V>(v),
ce_forward<W>(w)...);
}
Los ce_forward
plantillas de función son a constexpr
-marked std::forward
. (Algunas cosas en el estándar que podrían marcarse constexpr
no lo son). Estoy tratando de encontrar las cosas correctas para poner en el tipo de devolución y en los puntos de especificación de excepción. Algunos casos y advertencias que conozco son:
- El incorporada en
operator []
requiere un operando para ser un puntero de datos (o decaído referencia de matriz) y el otro para ser un tipo de enumeración o entero. Los operandos pueden estar en cualquier orden. No sé si un operando podría reemplazarse por un tipo de clase con una conversión inequívoca (¿no explícita?) A un tipo apropiado. - Un tipo de clase puede definir
operator []
como funciones miembro no estáticas. Cualquier función de este tipo solo puede tener un parámetro (además dethis
). - El operador incorporado no puede tirar. (A menos que los operandos se basen en una conversión UDT, dicha conversión es el único punto de lanzamiento posible). El comportamiento indefinido causado por los errores de límites está más allá de nuestro alcance aquí.
- Si la última llamada de indexación devuelve una referencia de valor l, la referencia de valor r o el valor debe reflejarse en el tipo de devolución de
slice
. - Si la llamada (final?) Es por valor, entonces
std::is_nothrow_move_constructible<ReturnType>::value
se debe OR a la especificación de excepción. (Los retornos por referencia sonnoexcept
). - Si el operador incorporado implica una matriz, la referencia devuelta para ese paso debe ser una referencia de valor r si la matriz también lo es. (Esto es un tipo de defecto porque los punteros, a diferencia de las matrices, pierden el estado del valor l- vs r del objetivo, por lo que la devolución tradicional siempre sería una referencia de valor l)
- Para operadores de indexación de clase, asegúrese de que las secciones de excepción-especificación y de tipo de devolución se refieran a la misma sobrecarga (si hay más de una) que utiliza el cuerpo de la función. Tenga cuidado con las sobrecargas que solo difieren en la calificación de
this
(const
/volatile
/ambos/ninguno y/o&
/&&
/ninguno).
Debe ser 'constexpr'? – kennytm
Para lo que lo estoy usando, debe ser 'constexpr' siempre que sea posible. – CTMacUser
¿Ha considerado simplemente poner la misma expresión que en la declaración 'return' para el tipo de retorno y la especificación' noexcept'? P.ej. 'noexcept (noexcept (std :: declval() [std :: declval ()])) -> decltype (std :: declval () [std :: declval ()])'. –