Python Нет функции возврата, имитирующей С++
Мне нравится функция в Python, которая может возвращать None, когда она не находит правильное возвращаемое значение. Например:
def get(self, key):
if key in self.db:
return self.db[key]
return None
Мне нужно реализовать ту же функцию в С++. Я думаю о некоторых возможностях.
Возвращает true/false, когда true получает значение из ссылки или указателя
bool get(string key, int& result)
{
if (in(key, db)) {
result = db[key];
return true;
}
return false;
}
Выслать сообщение об ошибке "Нет случая"
int get(string key) throw (int)
{
if (in(key, db)) {
result = db[key];
return result;
}
throw 0;
}
try {
....
}
catch (int n)
{
cout << "None";
}
Использовать пару
pair<bool, int> getp(int i)
{
if (...) {
return pair<bool, int>(true, 10);
}
return pair<bool,int>(false, 20);
}
pair<bool, int> res = getp(10);
if (res.first) {
cout << res.second;
}
Какой из них обычно используется в С++? Есть ли другие способы сделать это на С++?
Ответы
Ответ 1
Обычный способ С++ для этого (обратите внимание: С++ не является Python) должен возвращать итераторы из таких функций и возвращать end()
, когда элемент не может быть найден.
Если вы хотите использовать возвращаемые значения нетератора, используйте boost::optional
и возвращайте boost::none
, когда вы вернете Python None
.
Определенно не используйте throw
, если вы не ожидаете, что при нормальном выполнении никогда не будет иметь место ошибка.
Ответ 2
Я получил хорошее/плохое возвращаемое значение, используя небольшой настраиваемый Checked
шаблонный класс.
Мой фактический класс был немного более полным, включая операторы присваивания, строки причины ошибки и специализации для ссылочных типов и т.д., Поэтому я не использовал boost::optional<T>
. Я мог бы опубликовать полный класс, если есть интерес.
Общий смысл класса таков:
static const class Bad {} None;
template<typename ValueType>
class Checked
{
public:
// Constructor for good value.
Checked(ValueType x)
: value(x), valid(true)
{}
// Constructor for bad value.
Checked(Bad)
: value(), valid(false)
{}
operator ValueType(void) const
{
if (!valid)
;//assert or throw...
return value;
}
ValueType value;
bool valid;
};
Это можно использовать так:
Checked<int> Divide(int numerator, int denominator)
{
if (denominator == 0)
return Bad(); // or None;
return numerator / denominator; // Automatically uses the "good value" constructor
}
или
Checked<int> result = Divide(4, 5);
if (result.valid)
std::cout << result; // or result.value
else
std::cout << "Bad!";
Этот подход часто более эффективен, чем ссылочный подход из-за оптимизации возвращаемого значения.
Ответ 3
Я думаю, что разные проекты на С++ используют разные стандарты, но Return true/false, которые вы упомянули, может быть наиболее распространенным способом на С++, хотя некоторые люди предпочитают возвращать false при успешном выполнении, в то время как другие возвращают true на успех. В других случаях, если значение, которое вы хотели бы получить, является указателем, тогда возврат значения null является еще одним распространенным способом в С++.
Например, если вы работаете над проектами, связанными с Microsoft, то наиболее распространенным способом является возвращение HRESULT, что тип возврата, введенный Microsoft.
В linux функции обычно возвращают 0 при успехе, а ненулевое значение указывает код ошибки.
(вы можете найти эту дискуссию полезной).
Ответ 4
Я бы сказал, что эти три метода очень распространены в С++.
Само собой разумеется, что если тип возврата уже может иметь какое-то "недопустимое" или "зомбическое" состояние (например, как указатель NULL
или номер NaN
), то это может быть просто самым простым вещь для использования.
"Принимать выходной параметр по ссылке и возвращать код ошибки" - это более традиционный способ поведения в стиле C, который, конечно, очень распространен. Традиция состоит в том, чтобы вернуть 0 на успех и некоторый код ошибки при сбое (любое ненулевое значение).
"Выбрасывать исключение, если вы не можете вернуть значение", обычно имеет смысл, если вы принимаете исключения в своем коде. Это очень распространено, но не общепринятое (не все любят или используют исключения для тех же целей).
Эти первые два варианта находятся в бесконечной вражде (т.е. коды ошибок и исключения), и это действительно зависит от того, какую сторону вы выбираете. Итак, я бы назвал вас дебатами (что, конечно, слишком субъективно для StackOverflow).
"вернуть пару bool
и значение", я бы сказал, было менее распространено, но все же я видел это много раз. С принятием кортежей (boost::tuple
или std::tuple
(С++ 11)) и с использованием уровней (boost::tie
или std::tie
(С++ 11)) вся идея возврата нескольких значений из функция (как и многие языки) все более привлекательна и используется на практике.
Среди других вариантов у вас есть boost::optional<T>
, чье имя довольно самоочевидно (в основном, третий вариант (пара), завернутый в более красивый пакет). И у вас также может быть шаблон Alexandrescu Expected, который дает вам гибрид из всех трех вариантов, чтобы получить возвращаемое значение в комплекте с флагом, чтобы узнать, действительно ли оно или нет, и в комплекте с исключением, описывающим, почему он не может произвести значение, которое будет автоматически выбрано, если вы попытаетесь прочитать недопустимое значение. Однако для шаблона требуются функции С++ 11.
Ответ 5
При возврате указателя я могу использовать reinterpret_cast для возврата NULL.
class A
{
};
A* a(int i)
{
if (i == 0) return new A();
return reinterpret_cast<A*>(NULL);
}
int main(int argc, char *argv[]) {
A* result = a(1); // result is NULL
if (result == NULL) {
cout << "NULL returned";
}
result = a(0);
if (result != NULL) {
cout << "NON NULL returned";
}
}