Вызов конструктора с временным объектом


Я не понимаю следующей проблемы.

class InnerBox
{
public:
    InnerBox() : mContents(123) { };
private:
    int mContents;
};


class Box
{
public:

    Box(const InnerBox& innerBox) : mInnerBox(innerBox) { };

private:
    InnerBox mInnerBox;
};


void SomeFunction(const Box& box)
{
    return;
}

int main()
{
    Box box(InnerBox());  // !!PROBLEM!! Doesn't work: compiler thinks this is a function declaration
    SomeFunction(box);    // Error, cannot convert 'function pointer type' to const Box&

    return 0;
}

Полное сообщение об ошибке (Visual Studio 2010)

 error C2664: 'SomeFunction' : cannot convert parameter 1 from 'Box (__cdecl *)(InnerBox (__cdecl *)(void))' to 'const Box &'

Исправление простое:

int main()
{
    InnerBox innerBox;
    Box box(innerBox);  
    SomeFunction(box);

    return 0;
 }

Является ли это специфической проблемой MSVC, и если нет, Может ли кто-то объяснить, что причуда языка мешает мне позвонить Box box(InnerBox()); ?

3 4

3 ответа:

Вам нужно записать его как:

Box box((InnerBox()));

Или

Box box{InnerBox()};

Это не специфическая проблема MSVC. Правило в C++ состоит в том, чтобы рассматривать любую конструкцию, которая может быть объявлением, как объявление.

Без дополнительных скобок код объявляет функцию под названием box, которая возвращает Box и единственный аргумент которой является указателем на функцию, не принимающую никаких аргументов и возвращающую InnerBox. (Да -- InnerBox() фактически объявляет указатель на функцию (без имени), когда используется в параметре функции (это похоже на то, как Box[] фактически объявляет указатель на Box при использовании в качестве параметра функции)).

Исходный like анализируется как функцияобъявление (Неопределение ) для функции с именем 'box', которая возвращает Box и принимает в качестве параметра указатель функции, который возвращает InnerBox и не принимает параметров InnerBox (*)(). Смотрите это для хорошего описания самой неприятной проблемы синтаксического анализа.

Вы можете явно дифференцировать конструкцию объекта с помощью дополнительных скобок Box box((InnerBox()));. Или в качестве слегка более чистой альтернативы вы можете использовать новый синтаксис построения объектов C++11:

Box box{InnerBox()};

Является ли это специфической проблемой MSVC, и если нет, Может ли кто-нибудь объяснить, какая причуда языка мешает мне вызвать Box box(InnerBox()); ?

Для завершения других ответов:

Это известно как самый досадный разбор. Это не проблема с компилятором. Это в основном спецификация синтаксического анализа, которая говорит, что все, что может рассматриваться как объявление, рассматривается как объявление.

В вашем случае вы можете исправить это с помощью

Box box((InnerBox()));