2017-01-17 13 views
0

Является ли наиболее Vexing Parse коренится в двусмысленности относительно того, следует ли использовать void в качестве параметра объявления функции, которое не принимает аргументов?Указывает использование void в объявлении функции, которая не принимает аргументов, для параметра The Most Vexing Parse?

В качестве примера следующий код компилируется без ошибок и работает нормально, как для g ++ (v7.2.1), так и для Xcode (Apple LLVM version 7.0.2 (clang-700.1.81)).

#include <iostream> 

int asdf(void); 
int asdf(int a) { 
    return a; 
} 
int main() { 
    std::cout << asdf(6) << std::endl; //-> 6 
    return 0; 
} 

Это проходит весь путь обратно к стандарту ANSI-C и до, где пустой список параметров, указанный произвольное число аргументов. Это преследует нас сегодня с обратной совместимостью в компиляторах, которые, похоже, немного смущены этой проблемой. Должно ли вышеуказанное не вызывать предупреждение, если не выдавать ошибку?

Здесь у меня было прозрение (или, возможно, сон трубы). Может ли быть, что The Most Vexing Parse коренится в двусмысленности относительно использования void в списке декларации пустой функции?

Другой пример, Реферирование следующий Википедии пример:

class Timer { 
public: 
    Timer(); 
}; 

class TimeKeeper { 
public: 
    TimeKeeper(const Timer& t); 

    int get_time(); 
}; 

int main() { 
    TimeKeeper time_keeper(Timer()); 
    return time_keeper.get_time(); 
} 

Линия

TimeKeeper time_keeper(Timer()); 

, казалось бы, неоднозначным, так как оно может быть истолковано либо как

  • переменной определение переменной time_keeper класса TimeKe eper, инициализированный анонимным экземпляром класса Timer или
  • объявление функции для функции time_keeper, которая возвращает объект типа TimeKeeper и имеет один (неименованный) параметр, который является указателем на функцию возвращаемого типа Таймер (и не принимает вход). (См объект Function # В C и C++)

ССЫЛКА: https://en.wikipedia.org/wiki/Most_vexing_parse

Теперь, если мы указываем, что void необходимо использовать при объявлении функции без каких-либо переменных, разве это не удалить (не хаки, фундаментально удалить!) двусмысленность? Линия в вопросе стала бы тогда следующей, не оставляя никаких сомнений, что это объявление функции:

int main() { 
    TimeKeeper time_keeper(Timer(void)); 
    return time_keeper.get_time(); 
} 

Это проходит весь путь обратно в KNR, где обсуждается этот вопрос:

Поскольку специализированные версии getline и copy не имеют аргументов, логика предполагает, что их прототипы в начале файла должны быть getline() и copy(). Но для совместимости с старшими программами C стандарт принимает пустой список как объявление старого стиля и отключает проверку списка всех аргументов; слово void должно использоваться для явно пустого списка. [Керниган & Richie, язык программирования C, 1988, PGS 32-33]

и ..

Особое значение пустого списка аргументов предназначен для обеспечения старых программ C для скомпилировать с новыми компиляторами. Но это плохая идея для использования с новыми программами. Если функция принимает аргументы, объявите ; если он не принимает аргументов, используйте void [ibid, Pg. 73]

Ссылка: is f(void) deprecated in modern C and C++

+1

«Должно ли вышеуказанное не вызывать предупреждение, если не выдавать ошибку?» Нет. Почему ты так думаешь? Этот код объявляет две функции, предоставляет определение для одного из них и вызывает его. –

+2

Самый неприятный синтаксический разбор - как вы отделяете 'foo bar();' от функции с именем 'bar', возвращающей' foo' переменной переменной 'foo' с именем' bar', которая по умолчанию построена. – NathanOliver

+0

@latedeveloper 2, из-за несоответствия аргумента между объявлением функции и определением; в частности, декларация указывает аргументы '' void'', в то время как определение указывает целочисленный аргумент. – kmiklas

ответ

2

Определение функции также декларация. Это означает, что если у вас есть

int asdf(void); 
int asdf(int a) { 
    return a; 
} 

Вы объявили две версии asdf, один не принимая int и один принимая ничего. Затем перейти на использование версии int при использовании

std::cout << asdf(6) << std::endl; //-> 6 

Там нет ничего плохого в том, что, так как версия int определена.

Что бы проблема была бы, если вы пытаетесь использовать

asdf(); 

Когда вы сделаете это, так как она будет объявлена, но не определена, вы должны получить

неопределенная ссылка на `ASDF() '

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

+0

Ах, потому что список аргументов различен, сигнатура функции различна, а вызов '' asdf (6) '' будет соответствовать '' int asdf (int a) {'', correct? – kmiklas

+1

@kmiklas Да. Вы перегрузили функцию. Вы просто не указали определение перегрузки 'void'. – NathanOliver

+0

Thx. Я запутался в этом деле, чтобы искоренить решение The Most Vexing Parse, и пропустил лес через деревья. – kmiklas

2

Ваше предложение не полностью устранит двусмысленность.

Рассмотрим:

#include <string> 

struct Foo { ... }; 

int main(int argc, char **argv) { 
    Foo bar(std::string(argv[1])); 
} 

Это похоже, что это может быть объявить локальную переменную bar типа Foo, передавая std::string в конструктор.

Но что это на самом деле означает:

Foo bar(std::string *argv); 

Т.е. объявить bar как функцию, принимающую аргумент типа «указатель на std::string» и возвращающий Foo.

Этот пример не может быть исправлен путем добавления void.

 Смежные вопросы

  • Нет связанных вопросов^_^