помилка: запит для члена '..' в '..', який некласового типу


440

У мене є клас з двома конструкторами, один, який не бере аргументів, і той, який бере один аргумент.

Створення об'єктів за допомогою конструктора, який приймає один аргумент, працює як очікувалося. Однак якщо я створюю об’єкти за допомогою конструктора, який не бере аргументів, я отримую помилку.

Наприклад, якщо я компілюю цей код (використовуючи 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;
}

... я отримую таку помилку:

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 ()()’

Чому це так, і як я змушую його працювати?


пов'язані з : stackoverflow.com/q/2318650/69537
Meysam

Відповіді:


661
Foo foo2();

перейти

Foo foo2;

Ви отримуєте помилку, оскільки компілятор думає

Foo foo2()

за декларацією функції з назвою 'foo2' та типом повернення 'Foo'.

Але в такому випадку, якщо ми змінимося Foo foo2, компілятор може показати помилку " call of overloaded ‘Foo()’ is ambiguous".


6
Я не розумію, чому компілятор думає: Foo foo2 () щодо оголошення функції, всередині основної функції.
chaviaras michalis

Мабуть, я раніше приземлився на цю відповідь, оскільки не можу її знову підтвердити! Ось текстовий другий висновок ... і 2-й спасибі!
bigjosh

1
Оголошення функції без параметрів повинно було мати обов'язковий параметр "void", щоб це використання було дозволено з точки зору послідовності. Якщо я не помиляюсь, у K&R C було обов'язкове використання терміна void.
Раджеш

@Rajesh: Список недійсних параметрів не є обов'язковим, він просто означає щось інше (нульові параметри) із порожнього списку параметрів (невизначені параметри).
Ben Voigt

1
це ще одна вагома причина перейти на єдиний {} синтаксис ініціалізації, який вводиться в c ++ 11
Сумуду

41

Просто для запису ..

Це насправді не є рішенням вашого коду, але у мене було те саме повідомлення про помилку при неправильному доступі до методу екземпляра класу, на який вказував myPointerToClass, наприклад,

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

де

myPointerToClass->aMethodOfThatClass();

очевидно, було б правильно.


11

Додавши до бази знань, я отримав таку ж помилку для

if(class_iter->num == *int_iter)

Хоча IDE дав мені правильних членів для class_iter. Очевидно, проблема полягає в тому, "anything"::iteratorщо не має члена, який називається, numтому мені потрібно його знеструмити. Що не працює так:

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

... мабуть. Я врешті вирішив це з цим:

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

Я сподіваюся, що це допоможе тому, хто переживає це питання, як я.


8

Парентез не потрібний для створення екземпляра об'єкта класу, коли ви не збираєтесь використовувати конструктований параметр.

Просто використовуйте Foo foo2;

Це спрацює.


7

У мене була подібна помилка, здається, що компілятор неправильно розуміє виклик конструктору без аргументів. Я змусив це працювати, видаливши круглі дужки із змінної декларації у вашому коді приблизно так:

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
Це та сама відповідь, що і вище,
Greenonline

1
Найбільш дратівливий синтаксичний аналіз не так багато , що компілятор НЕ зрозумів, як це , що стандарт вимагає , щоб компілятор інтерпретувати все , що може бути оголошенням функції як оголошення функції, щоб запобігти двозначність.
Час Джастіна - Відновіть Моніку

( В зокрема, між [stmt.ambig/1]і [dcl.ambig.res/1], стандарт явно зазначено , що в разі неясності, все , що може бути витлумачено як декларація є декларацією, щоб вирішити цю неоднозначність.)
Justin Time - відновимо Моніка

2

Я наткнувся на випадок, коли мені надійшло повідомлення про помилку

Foo foo(Bar());

і в основному намагався передати в тимчасовий об'єкт Bar конструктору Foo. Виявляється, компілятор перекладав це на

Foo foo(Bar(*)());

тобто оголошення функції, ім'я якого foo, що повертає Foo, який бере аргумент - покажчик функції, що повертає смугу з 0 аргументами. При проходженні в таких часописах краще використовувати Bar{}замість того, Bar()щоб усунути неоднозначність.


0

Якщо ви хочете оголосити нову речовину без параметра (знаючи, що в об'єкта є параметри за замовчуванням), не пишіть

 type substance1();

але

 type substance;

0

Безумовно, важливий випадок цієї помилки, але я отримав її в іншій ситуації при спробі перевантажити завдання operator=. Це був трохи криптований ІМО (від 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;
}

Я отримав 2 "однакових" помилки

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

(Еквівалентна похибка clangстановить: error: member reference base type 'float' is not a structure or union)

для ліній data.i = data;і data.f = data;. Виявляється, компілятор плутав ім'я локальної змінної 'data' та мій змінний member data. Коли я змінив це на void operator=(T newData)і data.i = newData;, data.f = newData;помилка пішла.


0

@MykolaGolubyev вже дав чудові пояснення. Я шукав рішення зробити щось подібне, MyClass obj ( MyAnotherClass() )але компілятор інтерпретував це як декларацію функції.

C ++ 11 має встановлений в списку braced-init . Використовуючи це, ми можемо зробити щось подібне

Temp t{String()};

Однак це:

Temp t(String());

видає помилку компіляції, яку вона вважає tза типом 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;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.