У меня есть следующий класс с подписью метода, как показано ниже:
class Foo
{
public:
std::vector<std::string> barResults(const std::vector<std::string>&, const std::vector<std::string>&);
}
В файле реализации у меня есть следующее:
std::vector<std::string> Foo::barResults(const std::vector<std::string>& list1, const std::vector<std::string>& list2)
{
std::vector<std::string> results;
// small amount of implementation here...
return results;
}
Итак, я подумал про себя, давайте посмотрим, смогу ли я немного упростить эту сигнатуру функции с помощью некоторой автоматической магии, поскольку она становится "немного заполненной строкой"! Итак, я попробовал это ...
class Foo
{
public:
auto barResults(const std::vector<std::string>&, const std::vector<std::string>&);
}
auto Foo::barResults(const std::vector<std::string>& list1, const std::vector<std::string>& list2)
{
std::vector<std::string> results;
// small amount of implementation here...
return results;
}
Теперь, игнорируя тот факт, что да, я могу использовать «using namespace std», чтобы сильно его урезать, мне было интересно, почему компилятор выдал мне ошибку "функция, которая возвращает 'auto', не может использоваться до того, как она будет определена".
Я лично мог бы подумать, что компилятор легко сможет определить возвращаемый тип метода, но в данном случае это не так. Конечно, вы можете исправить это с помощью конечного возвращаемого типа, как показано ниже:
class Foo
{
public:
std::vector<std::string> barResults(const std::vector<std::string>&, const std::vector<std::string>&) -> std::vector<std::string>;
}
Но тогда, если вы воспользуетесь описанным выше, это будет не лучше, чем было раньше. Итак, помимо «использования пространства имен std», есть ли лучший способ сделать это, и почему компилятор не может определить возвращаемый тип в этом случае? Или даже, зависит ли это от того, как вызывается этот метод, из-за чего компилятор не может определить возвращаемый тип.





Проблема здесь в том, как работают включаемые файлы. Ваша ошибка:
a function that returns 'auto' cannot be used before it is defined
означает, что в файле вы используете свою функцию, ее определение (то есть реализация) не было нигде в файле до использования. Это означает, что компилятор, компилирующий ваш код с использованием функции, не может определить тип возвращаемого значения функции, поскольку для этого требуется доступ к определению (реализации). Наиболее вероятная причина этого в том, что определение (реализация) функции находится в ее собственном исходном файле (.cpp, .c и т. д.), Который не включен. Чтобы более полно понять это, я рекомендую прочитать ответ это и, возможно, ответ это.
Чтобы ответить на главный вопрос, вероятно, самый простой способ сократить эту подпись - использовать typedef. В частности, вы можете добавить следующий код везде, где считаете нужным, при условии, что область видимости подходит (я бы добавил его как публичный член в вашем классе):
typedef std::vector<std::string> strvec;
Это позволяет вам переписать подпись вашего метода как более управляемую:
strvec barreuslts(const strvec&, const strvec&)
Придерживаясь C++ 11, вы не можете полагаться на выведенные типы возвращаемого значения, вам нужен конечный тип возвращаемого значения (хотя C++ 14 допускает это). Поскольку в вашем случае нет ничего особенного в завершающем возвращаемом типе, т.е. никакое выражение не передается decltype для определения возвращаемого типа, я бы вместо этого попытался сократить сигнатуру метода с помощью некоторых псевдонимов типов:
class Foo
{
public:
using StrVec = std::vector<std::string>;
StrVec barResults(const StrVec&, const StrVec&);
};
Foo::StrVec Foo::barResults(const StrVec& list1, const StrVec& list2)
{
StrVec results;
// small amount of implementation here...
return results;
}
Это идея, о которой я уже думал, но этот код был для некоторых младших программистов и не хотел слишком усложнять вещи, используя что-то вроде typedef или using. Конечно, это хороший подход.
Я сомневаюсь, что введение автоматического возврата уменьшит сложность, в то время как использование определения типа в классе с разумным именем может сделать код более читаемым. Кстати, я бы использовал объявление C++ 11 -> StrVec синтаксиса конечного возвращаемого типа, чтобы избавиться от надоедливого Foo :: в начале, хотя в конце это стоит 2 дополнительных символа для Foo!
Если вы просто ищете визуально привлекательный способ работы с более длинными подписями, перестаньте заставлять все располагаться в одной строке. Будьте либеральны с вертикальным интервалом и вставляйте разрывы строк. Подпись содержит качественную информацию для вызывающего абонента, и вы, возможно, ищете многострочную подпись. Если вы работаете с шириной страницы 80 символов, пересмотрите отступ в спецификаторе доступа.
class Foo
{
public:
std::vector<std::string> barResults(const std::vector<std::string>&,
const std::vector<std::string>&);
}
std::vector<std::string>
Foo::barResults(const std::vector<std::string>& list1,
const std::vector<std::string>& list2)
{
std::vector<std::string> results;
// small amount of implementation here...
return results;
}
Когда дело доходит до разделения объявления, существует множество стилей. Наличие такого инструмента, как clang-format в вашем наборе инструментов, сделает это автоматически и последовательно за вас.
Обычно я либерально отношусь к пробелам, но это скорее сложный вопрос как о форматировании, так и о том, что вызвало ошибку. Я также НЕТ поклонник использования auto везде, как и вы, я согласен с тем, что подпись содержит информацию о качестве. Просто в этом случае подпись была довольно многословной, и когда я хотел ее немного укоротить, с небольшим использованием auto, возникла ошибка, которой я не ожидал. Теперь, когда кто-то указал на это, становится понятным, почему это произошло.
Как я уже сказал выше, использование typedef или using было тем, что я уже рассматривал, и я действительно хотел только немного сократить длину строки, не меняя всю подпись. Однако я еще не подумал о другом, о чем вы отметили. Поскольку я включаю только заголовок и эту реализацию, необходимую для вывода типа, это причина, по которой я получил ошибку. Хороший.