Построение объекта / Неоднозначность объявления функции вперед - PullRequest
7 голосов
/ 16 февраля 2010

Observation: the codes pasted below were tested only with GCC 4.4.1, and I'm only interested in them working with GCC.

Здравствуйте,

Не несколько раз я наталкивался на утверждение о создании объекта, которого я не понимал, и только сегодня я заметил, какую двусмысленность он вносит. Я объясню, как воспроизвести его, и хотел бы знать, есть ли способ исправить это (разрешен C ++ 0x). Вот и все.

Предположим, есть класс, конструктор которого принимает только один аргумент, и тип этого аргумента - это другой класс с конструктором по умолчанию. E.g.:

struct ArgType {};

class Class
{
public:
    Class(ArgType arg);
};

Если я пытаюсь построить объект типа Class в стеке, я получаю неоднозначность:

Class c(ArgType()); // is this an object construction or a forward declaration
                    // of a function "c" returning `Class` and taking a pointer
                    // to a function returning `ArgType` and taking no arguments
                    // as argument? (oh yeh, loli haets awkward syntax in teh
                    // saucecode)

Я говорю, что это конструкция объекта, но компилятор настаивает, что это предварительное объявление внутри тела функции. Для тех, кто до сих пор не понял, вот полностью рабочий пример:

#include <iostream>

struct ArgType {};
struct Class {};

ArgType func()
{
    std::cout << "func()\n";
    return ArgType();
}

int main()
{
    Class c(ArgType());

    c(func); // prints "func()\n"
}

Class c(ArgType funcPtr()) // Class c(ArgType (*funcPtr)()) also works
{
    funcPtr();
    return Class();
}

Итак, достаточно примеров. Кто-нибудь может помочь мне обойти это, не делая ничего слишком анти-идиоматического (я разработчик библиотек, и такие люди, как идиоматические библиотеки)?

- редактировать

Неважно. Это обман Самый неприятный анализ: почему не A a (()); работа .

Спасибо, sbi.

Ответы [ 3 ]

6 голосов
/ 16 февраля 2010

Это известно как "самый неприятный синтаксический анализ C ++". См. здесь и здесь .

1 голос
/ 16 февраля 2010

Давайте немного упростим.

int f1();

Что это? Компилятор (и я) говорят, что это предварительное объявление для функции, возвращающей целое число.

Как насчет этого?

int f2(double );

Компилятор (и я) говорят, что это предварительное объявление для функции, принимающей двойной аргумент и возвращающей int.

Итак, вы пробовали это:

ClassType c = ClassType(ArgType());

Проверьте c ++ faq lite на конструкторах для объяснений и примеров

1 голос
/ 16 февраля 2010

Исходя из "C ++ 0x позволено", правильный ответ (вероятно) состоит в том, чтобы изменить определение на:

Class c(ArgType {});

Простой, простой и полностью обременяющий пользователя библиотеки, а не автор!

Редактировать: Да, вызывается ctor - C ++ 0x добавляет List-Initialization как однозначный способ разграничения списков инициализатора.Это не может быть неправильно проанализировано, как в вашем примере, но в остальном значение примерно такое же, как если бы вы использовали круглые скобки.См. N3000 , третий пункт в п. 8.5.5 / 3.Вы можете написать ctor для получения списка инициализаторов в виде одного аргумента, или элементы в списке инициализаторов могут быть сопоставлены с аргументами ctor по отдельности.

...