erreur: demande pour le membre '..' dans '..' qui est de type non-classe


440

J'ai une classe avec deux constructeurs, un qui ne prend aucun argument et un qui prend un argument.

La création d'objets à l'aide du constructeur qui prend un argument fonctionne comme prévu. Cependant, si je crée des objets à l'aide du constructeur qui ne prend aucun argument, j'obtiens une erreur.

Par exemple, si je compile ce code (en utilisant g ++ 4.0.1) ...

class Foo
{
  public:
    Foo() {};
    Foo(int a) {};
    void bar() {};
};

int main()
{
  // this works...
  Foo foo1(1);
  foo1.bar();

  // this does not...
  Foo foo2();
  foo2.bar();

  return 0;
}

... j'obtiens l'erreur suivante:

nonclass.cpp: In function int main(int, const char**)’:
nonclass.cpp:17: error: request for member bar in foo2’, which is of non-class type Foo ()()’

Pourquoi est-ce et comment puis-je le faire fonctionner?


Réponses:


662
Foo foo2();

changer pour

Foo foo2;

Vous obtenez l'erreur parce que le compilateur pense

Foo foo2()

à partir de la déclaration de fonction avec le nom 'foo2' et le type de retour 'Foo'.

Mais dans ce cas, si nous passons à Foo foo2, le compilateur peut afficher l'erreur " call of overloaded ‘Foo()’ is ambiguous".


6
Je ne comprends pas pourquoi le compilateur pense: Foo foo2 () comme déclaration de fonction, à l'intérieur de la fonction principale.
chaviaras michalis

Apparemment, j'ai déjà atterri sur cette réponse car je ne peux pas la voter à nouveau! Voici un 2e vote positif textuel ... et un 2e merci!
bigjosh

1
La déclaration de fonction sans paramètre aurait dû rendre obligatoire le paramètre "void" pour que cette utilisation ait été autorisée du point de vue de la cohérence. Si je ne me trompe pas, K&R C avait l'utilisation obligatoire du terme nul.
Rajesh

@Rajesh: Une liste de paramètres nulle n'est pas obligatoire, cela signifie simplement quelque chose de différent (zéro paramètre) d'une liste de paramètres vide (paramètres non spécifiés).
Ben Voigt

1
c'est une autre bonne raison de passer à la syntaxe d'initialisation {} uniforme introduite dans c ++ 11
Sumudu

41

Juste pour info..

Ce n'est en fait pas une solution à votre code, mais j'ai eu le même message d'erreur lors d'un accès incorrect à la méthode d'une instance de classe pointée par myPointerToClass, par exemple

MyClass* myPointerToClass = new MyClass();
myPointerToClass.aMethodOfThatClass();

myPointerToClass->aMethodOfThatClass();

serait évidemment correct.


11

En ajoutant à la base de connaissances, j'ai eu la même erreur pour

if(class_iter->num == *int_iter)

Même si l'IDE m'a donné les bons membres pour class_iter. De toute évidence, le problème est qu'il "anything"::iteratorn'y a pas de membre appelé, numdonc je dois le déréférencer. Ce qui ne fonctionne pas comme ça:

if(*class_iter->num == *int_iter)

...Apparemment. Je l'ai finalement résolu avec ceci:

if((*class_iter)->num == *int_iter)

J'espère que cela aide quelqu'un qui traverse cette question comme je l'ai fait.


8

La parenthèse n'est pas requise pour instancier un objet classe lorsque vous n'avez pas l'intention d'utiliser un constructeur paramétré.

Utilisez simplement Foo foo2;

Ça va marcher.


7

J'avais une erreur similaire, il semble que le compilateur comprenne mal l'appel au constructeur sans arguments. Je l'ai fait fonctionner en supprimant les parenthèses de la déclaration de variable, dans votre code quelque chose comme ceci:

class Foo
{
  public:
    Foo() {};
    Foo(int a) {};
    void bar() {};
};

int main()
{
  // this works...
  Foo foo1(1);
  foo1.bar();

  // this does not...
  Foo foo2; // Without "()" 
  foo2.bar();

  return 0;
}

1
C'est la même réponse que celle ci
Greenonline

1
L' analyse la plus contrariante n'est pas tant que le compilateur a mal compris, car c'est que la norme exige que le compilateur interprète tout ce qui pourrait être une déclaration de fonction comme une déclaration de fonction, pour éviter toute ambiguïté.
Justin Time - Réintègre Monica

(Plus précisément, entre [stmt.ambig/1]et [dcl.ambig.res/1], la norme stipule explicitement qu'en cas d'ambiguïté, tout ce qui peut être interprété comme une déclaration EST une déclaration, pour résoudre cette ambiguïté.)
Justin Time - Rétablir Monica

2

Je suis tombé sur un cas où j'ai reçu ce message d'erreur et

Foo foo(Bar());

et essayait essentiellement de passer un objet Bar temporaire au constructeur Foo. Il s'avère que le compilateur traduisait cela en

Foo foo(Bar(*)());

c'est-à-dire une déclaration de fonction dont le nom est foo qui renvoie un Foo qui accepte un argument - un pointeur de fonction renvoyant une barre avec 0 arguments. Lors du passage dans des temporaires comme celui-ci, mieux vaut utiliser Bar{}plutôt que d' Bar()éliminer l'ambiguïté.


0

Si vous voulez déclarer une nouvelle substance sans paramètre (sachant que l'objet a des paramètres par défaut) n'écrivez pas

 type substance1();

mais

 type substance;

0

Certes, un cas d'angle pour cette erreur, mais je l'ai reçu dans une situation différente, lorsque j'essayais de surcharger l'affectation operator=. C'était un peu crypté IMO (de g ++ 8.1.1).

#include <cstdint>

enum DataType
{
  DT_INT32,
  DT_FLOAT
};

struct PrimitiveData
{
  union MyData
  {
    int32_t i;
    float f;
  } data;

  enum DataType dt;

  template<typename T>
  void operator=(T data)
  {
    switch(dt)
    {
      case DT_INT32:
      {
        data.i = data;
        break;
      }
      case DT_FLOAT:
      {
        data.f = data;
        break;
      }
      default:
      {
        break;
      }
    }
  }
};

int main()
{
  struct PrimitiveData pd;
  pd.dt = DT_FLOAT;
  pd = 3.4f;

  return 0;
}

J'ai reçu 2 erreurs "identiques"

error: request for member i [and 'f'] in data’, which is of non-class type float

(L'erreur équivalent clangest la suivante : error: member reference base type 'float' is not a structure or union)

pour les lignes data.i = data;et data.f = data;. Il s'avère que le compilateur confondait le nom de variable locale «données» et ma variable membre data. Quand j'ai changé cela void operator=(T newData)et data.i = newData;, data.f = newData;l'erreur a disparu.


0

@MykolaGolubyev a déjà donné de merveilleuses explications. Je cherchais une solution pour faire quelque chose comme ça, MyClass obj ( MyAnotherClass() )mais le compilateur l'interprétait comme une déclaration de fonction.

C ++ 11 a braced-init-list . En utilisant cela, nous pouvons faire quelque chose comme ça

Temp t{String()};

Cependant, ceci:

Temp t(String());

jette une erreur de compilation car il considère tcomme de type Temp(String (*)()).

#include <iostream>

class String {
public:
    String(const char* str): ptr(str)
    {
        std::cout << "Constructor: " << str << std::endl;
    }
    String(void): ptr(nullptr)
    {
        std::cout << "Constructor" << std::endl;
    }
    virtual ~String(void)
    {
        std::cout << "Destructor" << std::endl;
    }

private:
    const char *ptr;
};

class Temp {
public:
    Temp(String in): str(in)
    {
        std::cout << "Temp Constructor" << std::endl;
    }

    Temp(): str(String("hello"))
    {
        std::cout << "Temp Constructor: 2" << std::endl;
    }
    virtual ~Temp(void)
    {
        std::cout << "Temp Destructor" << std::endl;
    }

    virtual String get_str()
    {
        return str;
    }

private:
    String str;
};

int main(void)
{
    Temp t{String()}; // Compiles Success!
    // Temp t(String()); // Doesn't compile. Considers "t" as of type: Temp(String (*)())
    t.get_str(); // dummy statement just to check if we are able to access the member
    return 0;
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.