Проверьте определенность значения в C ++ - PullRequest
6 голосов
/ 23 января 2009

Я работаю в C ++ и мне нужно знать, определено ли скалярное значение (например, double) или нет. Я также должен быть в состоянии "undef" это при необходимости:

class Foo {
public:
    double get_bar();

private:
    double bar;
    void calculate_bar() {
        bar = something();
    }
};

double Foo::get_bar() {
    if ( undefined(bar) )
        calculate_bar();
    return bar;
}

Возможно ли это в C ++?

Спасибо

Ответы [ 9 ]

12 голосов
/ 23 января 2009

Как говорится в других ответах, C ++ не имеет этой концепции. Вы можете легко обойти это, хотя.

Либо у вас может быть неопределенное значение, которому вы инициализируете bar в конструкторе, обычно -1.0 или что-то подобное.

Если вы знаете, что Calculate_bar никогда не возвращает отрицательные значения, вы можете реализовать неопределенную функцию в качестве проверки для <0.0. </p>

Более общим решением является использование bool, говорящего о том, определен ли бар, но что вы инициализировали значение false в конструкторе, и когда вы впервые устанавливаете его, вы меняете его на true. boost :: необязательный делает это элегантным шаблонным способом.

Вот как будет выглядеть пример кода.

class Foo {
public:
    double get_bar();
    Foo() : barDefined(false) {}
private:
    double bar;
    bool barDefined;
    void calculate_bar() {
        bar = something();
    }
};

double Foo::get_bar() {
    if ( barDefined == false ) {
        calculate_bar();
        barDefined = true;
    }
    return bar;
}
6 голосов
/ 23 января 2009

Как отмечали другие, нет ничего похожего на "неопределенное" состояние. Но вы можете посмотреть на boost.optional

3 голосов
/ 23 января 2009

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

edit: программист должен обрабатывать состояние объекта в конструкторах и / или ручных методах инициализации, таких как init()

2 голосов
/ 23 января 2009

Почему бы не сохранить отдельный флаг, который инициализируется как false, а затем устанавливается в true при расчете бара. Затем его можно «отменить», снова установив флаг на «ложь».

if(!isBarValid)
{
    calculateBar();
    isBarValid = true;
}
return bar;
1 голос
/ 23 января 2009

Это невозможно в C / C ++, примитивам всегда будет присвоено значение (в основном мусор, что бы ни находилось в этом месте в памяти до него, если это явно не назначено при объявлении). Я обычно имею значение-заполнитель (то есть 0 для указателей), которое обозначает неиспользуемые, однако они также должны быть явно назначены. Если ваш двойник может принять какое-либо значение, то я предлагаю вам поставить рядом с ним логическое значение, изначально присвоенное ложному, и проверить / установить его, когда вы хотите выполнить вычисления.

1 голос
/ 23 января 2009

C ++ не имеет неопределенного состояния для примитивных типов. Ближайшим доступным для float / double будет NAN, но это действительно имеет другое значение.

0 голосов
/ 23 января 2009

Вы можете попробовать Construct при первом использовании идиома и написать get_bar() так:

double & get_bar()
{
    static double *bar = new double(something());
    return *bar;
}

Когда вы звоните get_bar(), вы получите bar, если никто еще не попросил об этом. Любые последующие звонки просто вернут bar. Как сказано на связанной странице, технически это не приводит к утечке памяти, потому что ОС восстановит ее при выходе из программы.

UPDATE:

Изменено возвращаемое значение на double &, чтобы можно было изменить bar.

0 голосов
/ 23 января 2009

Вы должны сделать это с помощью дополнительного логического значения.

Чтобы реализовать использование дополнительного логического значения, вы можете попробовать логику, как в следующем шаблоне:

template<typename T>
struct Defined
{
 bool defined;
 T value;
 Defined() : defined(false) {}
 Defined(const T& value_) : defined(true), value(value_) {}
 ... and perhaps other operators here ...
 ... to make this behave even more like a T ...
};
0 голосов
/ 23 января 2009

Инициализируйте bar некоторым значением, которое никогда не может возникнуть при вызове функции something() в конструкторе.

Например:

Foo(): bar(-1)
{
}

Затем проверьте значение -1 в функции get_bar.

(хммм Ласераллан также отправил ответ за 1 минуту до этого :-( ;-))

...