Неоднозначность построения объекта/форвардной функции

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). Вот оно.

Предположим, что есть класс, конструктор которого принимает только один аргумент, и тип этого одного аргумента является другим классом с конструктором по умолчанию. Например.:

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(() ); работать?.

Спасибо, сби.


person Gui Prá    schedule 16.02.2010    source источник
comment
Ваш код компилируется для меня с помощью g++ - как вы думаете, какой бит не должен работать?   -  person    schedule 16.02.2010
comment
Дело не в том, работает или не работает. Проблема в том, что я просто хотел создать объект типа Class и передать его конструктору объект типа ArgType, созданный встроенным. Но он распознается как предварительное объявление. Я добавлю код, который я хотел заставить работать, но не могу, секундочку.   -  person Gui Prá    schedule 16.02.2010
comment
Забудь об этом, Нил. Посмотрите на ответ sbi, это именно моя проблема.   -  person Gui Prá    schedule 16.02.2010


Ответы (3)


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

person sbi    schedule 16.02.2010
comment
@ArnavBorborah Спасибо, удалено. - person sbi; 17.04.2018

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

int f1();

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

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

int f2(double );

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

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

ClassType c = ClassType(ArgType());

Ознакомьтесь с облегчённым списком часто задаваемых вопросов по c++ в конструкторах для объяснения и примеры

person Liz Albin    schedule 16.02.2010

Основываясь на «С++ 0x разрешено», правильный ответ (вероятно) состоит в том, чтобы изменить определение на:

Class c(ArgType {});

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

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

person Jerry Coffin    schedule 16.02.2010
comment
Подождите... но это же не вызовет конструктор, не так ли? - person Gui Prá; 16.02.2010
comment
На самом деле это не кажется приемлемым для GCC 4.4.1. Однако другие комбинации: Class c{ArgType {}}; или Class c{ArgType ()}; И добавление версии вызова конструктора, отличной от C++0x: Class c((ArgType ())); - person UncleBens; 16.02.2010