9
votes

C ++ moulage au tableau d'une taille plus petite

Voici une question intéressante sur les différentes bizarreries de la langue C ++. J'ai une paire de fonctions, qui sont censées remplir un éventail de points avec les coins d'un rectangle. Il y a deux surcharges pour cela: on prend un point [5] , l'autre prend un point [4] . La version à 5 points fait référence à un polygone fermé, tandis que la version à 4 points est lorsque vous voulez juste que vous voulez juste les 4 coins, la période.

Il y a évidemment une certaine doublégication du travail ici, alors j'aimerais pouvoir utiliser le Version à 4 points pour remplir les 4 premiers points de la version à 5 points, donc je ne fais pas dupliquer ce code. (Pas que c'est beaucoup à dupliquer, mais j'ai des réactions allergiques terribles chaque fois que je copierais et coller du code, et j'aimerais éviter cela.)

La chose est, c ++ ne semble pas se soucier L'idée de convertir un t [m] à un t [n] n . static_cast semble penser que les types sont incompatibles pour une raison quelconque. REINIERPRET_CAST gère bien, bien sûr, mais est un animal dangereux qui, en règle générale, est préférable d'éviter si possible si possible.

Donc, ma question est de: Un moyen sûr de la création d'une matrice d'une taille à un tableau de taille plus petite où le type de matrice est le même?

[modifier] Code, oui. J'aurais dû mention que le paramètre est en réalité une référence à un tableau, pas simplement un pointeur, le compilateur est donc au courant de la différence de type. xxx

[EDIT2] Le point de transmettre un tableau par référence est de sorte que nous puissions être au moins vaguement sûrs que l'appelant passe dans un "paramètre OUT" correct.


2 commentaires

S'il vous plaît poster le code, spécifiquement vos déclarations de fonction. Les fonctions déclaralisées pour prendre des paramètres car les tableaux prennent des paramètres comme des pointeurs afin que vous ne puissiez pas surcharger par une différence de taille de tableau d'un paramètre.


J'aurais dû mentionné qu'ils sont en réalité des matrices-par-référence. Le compilateur maintient donc la sensibilisation à la taille de la matrice.


6 Réponses :


5
votes

Je ne pense pas que ce soit une bonne idée de le faire en surcharge. Le nom de la fonction ne dit pas à l'appelant s'il va remplir un tableau ouvert ou non. Et que si l'appelant a seulement un pointeur et veut remplir des coordonnées (disons qu'il veut remplir de multiples rectangles pour faire partie d'un tableau plus gros dans des décalages différents)?

Je ferais cela par deux fonctions et laissez-les prendre pointeurs. La taille ne fait pas partie du type du pointeur p> xxx pré>

Je ne vois pas ce qui ne va pas avec ça. Votre réinterpret devrait fonctionner correctement dans la pratique (je ne vois pas ce qui pourrait aller mal - l'alignement et la représentation seront corrects, de sorte que la simple formelle indéfinie n'active pas la réalité ici, je pense), mais comme je l'ai dit ci-dessus, je pense qu'il n'y a pas de bonne raison pour que ces fonctions prennent les matrices par référence. p>


Si vous souhaitez le faire de manière générale, vous pouvez l'écrire par les itérateurs de sortie P>

std::vector<degPoint> points;
fillClosedRect(someRect, std::back_inserter(points));

degPoint points[5];
fillClosedRect(someRect, points);


2 commentaires

En passant une référence à un tableau, le compilateur effectuera la vérification du type et la vérification de la taille de la matrice est correcte, donnant une erreur de temps de compilation si la remplissage à tort est appelée à un recto de 4 points. Est-il possible de static_cast un tableau d'une taille à une matrice de taille différente?


@Stephen Il n'est pas possible de jeter de telles choses statiques. Mais le point du compilateur vérifie qu'il est discutable. Vous ne pouvez transmettre que des tableaux de cette taille spécifique et même si la taille est vérifiée par le compilateur - qui ne couvre que les contrôles de type. Cela ne garantit pas que la référence fera référence à un objet de réseau approprié. Les références pendantes seront toujours possibles si l'appelant gâche quelque part. Je suis tout pour la vérification du temps compilé, mais dans ce cas, cela ne semble pas avantage.



3
votes

J'utiliserais std :: vecteur ou (c'est vraiment mauvais et ne doit pas être utilisé) dans certains cas extrêmes, vous pouvez même utiliser des tableaux simples via un pointeur comme < Code> Point * Et puis vous ne devriez pas avoir de tellement "casting" problèmes.


0 commentaires

1
votes

Pourquoi ne pas simplement passer un pointeur standard, au lieu d'une taille, comme celui-ci xxx


1 commentaires

C'est discutable. Cette fonction est de remplacer un nombre de cas où cette conversion est effectuée manuellement et, dans tous les cas, sans exception, l'ensemble des points est conservé dans un tableau de pile qui est jeté à la fin de la portée, de sorte que la taille ne soit pas un problème. (et cette opération sur un tableau de démarrage n'aurait aucun sens à l'application). Le but ici est de, en général, de jeter des erreurs de compilateur plutôt que d'avoir des violations d'accès qui doivent ensuite être retrouvées dans le cadre de la base de code massif.



0
votes

Je suppose que vous pouvez utiliser la spécialisation des modèles de fonction, comme celui-ci (exemple simplifié où le premier argument a été ignoré et que le nom de la fonction a été remplacé par F (), etc.):

#include <iostream>
using namespace std;

class X
{
};

template<int sz, int n>
int f(X (&x)[sz])
{
    cout<<"process "<<n<<" entries in a "<<sz<<"-dimensional array"<<endl;
    int partial_result=f<sz,n-1>(x);
    cout<<"process last entry..."<<endl;

    return n;
}
//template specialization for sz=5 and n=4 (number of entries to process)
template<>
int f<5,4>(X (&x)[5])
{
    cout<<"process only the first "<<4<<" entries here..."<<endl;

    return 4;
}


int main(void)
{
    X u[5];

    int res=f<5,5>(u);
    return 0;
}


0 commentaires

1
votes

Je ne pense pas que votre cadrage / penser au problème est correct. Vous n'avez généralement pas besoin de saisir concrètement un objet qui a 4 sommets vs un objet qui a 5.

mais si vous devez le taper, vous pouvez utiliser struct s pour définir concrètement les types. à la place. xxx

puis xxx

puis, xxx

Je pense que cette solution est un peu extrême cependant et un std :: vecteur que vous vérifiez sa taille (4 ou 5) comme prévu avec affirmation s, ferait juste bien.


1 commentaires

Ce n'est pas vraiment une option. Étiez-vous un nouveau projet que je suis d'accord avec vous, mais c'est un programme extrêmement ancien et que le niveau de refactoring n'est tout simplement pas sur la feuille de route pour le moment. Merci pour la suggestion cependant. :)



0
votes

Donc, ma question est: y a-t-il un façon de type-sécurité de casser un tableau de une taille à un tableau d'une taille plus petite où le type de matrice est le même? p>

non. Je ne pense pas que la langue vous permet de le faire du tout: envisager de casting int [10] sur INT [5]. Vous pouvez toujours obtenir un pointeur, cependant, mais nous ne pouvons pas "tromper" le compilateur à penser qu'une taille fixe a un nombre différent de dimensions. P>

Si vous n'allez pas utiliser STD :: Vecteur ou un autre conteneur pouvant identifier correctement le nombre de points à l'intérieur au moment de l'exécution et faire tout cela commodément dans une seule fonction au lieu de deux surcharges de fonction qui sont appelées appelées sur le nombre d'éléments, plutôt que d'essayer de faire des moules folles, envisagez Ceci au moins comme une amélioration: p> xxx pré>

Si vous êtes défini sur Utiliser avec des tableaux, vous pouvez toujours définir une fonction générique comme ceci: P>

template <size_t N>
void RectToPointArray(const degRect& rect, degPoint(&points)[N])
{
    assert(N >= 4 && "points requires at least 4 elements!");
    points[0].lat = rect.nw.lat; points[0].lon = rect.nw.lon;
    points[1].lat = rect.nw.lat; points[1].lon = rect.se.lon;
    points[2].lat = rect.se.lat; points[2].lon = rect.se.lon;
    points[3].lat = rect.se.lat; points[3].lon = rect.nw.lon;

    if (N >= 5)
        points[4].lat = rect.nw.lat; points[4].lon = rect.nw.lon;
}


0 commentaires