Conversion de C++ char* [] en char**

j'ai ce code simple qui compile sans erreurs/avertissements:

void f(int&, char**&){}

int main(int argc, char* argv[])
{
    f(argc, argv);
    return 0;
}

Et suivant le même code qui ne compile pas:

void f(int&, char**&){}

int main()
{
    int argc = 2;
    char* argv[] = { "", "", nullptr };
    f(argc, argv); 
    //@VS2013 error: cannot convert argument 2 from 'char *[3]' to 'char **&'
    //@GCC error: invalid initialization of non-const reference of type 'char**&' from an rvalue of type 'char**'
    return 0;
}

Pourquoi char*[] peut être converti char**& dans le premier échantillon et ne peut pas être convertie dans le deuxième exemple? Est-ce important que la taille soit connue au moment de la compilation?

EDIT: je pense qu'il y a 2 conversions nécessaires dans le second cas, et une seule conversion implicite peut être faite par compilateur.

ce code compile:

void f(int&, char**&){}

int main()
{
    int argc = 2;
    char* temp[] = { "", "", nullptr };
    char** argv = temp;
    f(argc, argv);
    return 0;
}
14
demandé sur Felics 2013-12-09 13:42:57

3 réponses

Jefffrey commentaire les références de la norme, elle est ici:

4.2 conversion tableau-à-pointeur [conv.tableau]

Une lvalue ou rvalue de type "tableau de N T" ou "tableau de l'inconnu lié de T" peuvent être convertis à une valeur de type "pointer vers T". Le résultat est un pointeur vers l' premier élément du tableau.

Et un prvalue est:

une prvalue ("pure" rvalue) est une expression qui identifie temporaire objet (ou un sous-objet de celui-ci) ou est une valeur associée à aucun objet.

vous ne pouvez pas lier une référence non-const à un temporaire.

int& i = int(); // error

char* argv[] = { "", "", nullptr };
// the result of the conversion is a prvalue
char**& test = argv; // error

par conséquent le code suivant sera compilé avec plaisir:

#include <iostream>

void f(int& argc, char** const& argv){
    std::cout << argv[0] << std::endl; // a
}

int main()
{
    int argc = 2;
    char* argv[] = { "a", "b", nullptr };
    f(argc, argv); 
    return 0;
}

une chose importante sur laquelle j'ai glissé est indiquée dans commentaire de Kanze.

Dans le premier exemple fourni dans l'OP, char* argv[] et char** argv sont équivalents. Par conséquent, il n'y a pas de conversion.

std::cout << std::is_array<decltype(argv)>::value << std::endl; // false
std::cout << std::is_array<char**>::value << std::endl; // false
std::cout << std::is_array<char*[]>::value << std::endl; // true
std::cout << std::is_same<decltype(argv), char**>::value << std::endl; // true
std::cout << std::is_same<decltype(argv), char*[]>::value << std::endl; // false
3
répondu Community 2017-05-23 12:23:40

Parce que malgré les apparences, le deuxième argument de main a type char**. Lorsqu'il est utilisé comme la déclaration d'une fonction argument, une pile de niveau supérieur est réécrit à un pointeur, donc char *[] est, en fait, char**. Cela s'applique uniquement à la fonction les paramètres, cependant.

char*[] (comme dans votre deuxième cas) permet de convertir un char**, mais les résultats de la conversion (comme toute conversion) est un R valeur, et ne peut pas être utilisé pour initialiser une référence non-const. Pourquoi pensez-vous voulez la référence? Si c'est pour modifier le pointeur, la modification de l' char** argument main est un comportement indéfini (formellement, en C, au moins-je n'ai pas vérifié si C++ est plus libéral ici). Et bien sûr, il n'y a aucun moyen que vous puissiez modifier la constante de l'adresse d'un tableau. Et si vous ne voulez pas pour le modifier, pourquoi utiliser une référence?

8
répondu James Kanze 2013-12-09 10:16:54

le type de temp

char* temp[] = { "", "", nullptr };

char* []

char*[3]

ce dernier ne peut pas être implicitement converti en `char**'.

main, le type de argv indépendant char* array qui est équivalent à char**

j'avoue, c'est source de confusion :)

0
répondu egur 2013-12-09 10:40:09