Реализация переменных переменных в C ++ - PullRequest
3 голосов
/ 15 апреля 2009

Я искал пример, который показывает, как реализовать ограничения в C ++ (или библиотеку наддува, которая позволяет мне легко это делать), но без особой удачи. Лучшее, что я смог придумать, это:

#include <boost/function.hpp>
#include <boost/lambda/lambda.hpp>

template<typename T>
class constrained
{
    public:
        constrained(boost::function<bool (T)> constraint, T defaultValue, T value = defaultValue)
        {
            ASSERT(constraint(defaultValue));
            ASSERT(constraint(value));

            this->value = value;
            this->defaultValue = defaultValue;          
            this->constraint = constraint;                      
        }

        void operator=(const T &assignedValue)
        {
            if(constraint(assignedValue))
                value = assignedValue;      
        }   

    private:
        T value;
        T defaultValue;
        boost::function<bool (T)> constraint;
};

int main(int argc, char* argv[])
{
    constrained<int> foo(boost::lambda::_1 > 0 && boost::lambda::_1 < 100, 5, 10);

    foo = 20; // works
    foo = -20; // fails

    return 0;
}

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

В любом случае, проблема, с которой я сталкиваюсь, заключается в том, что я должен перегрузить все операторы, которые определяет T, чтобы заставить его действительно вести себя как T, и у меня нет способа узнать, что это такое. Теперь мне не нужны ограничения для такого множества различных типов, поэтому я мог бы просто пропустить шаблон и жестко их кодировать. Тем не менее, мне интересно, есть ли общее (или, по крайней мере, более лаконичное / элегантное) решение или что-то серьезно не так с моим подходом.

Ответы [ 6 ]

4 голосов
/ 15 апреля 2009

выглядит хорошо, как на крошечном примере. Но обязательно реализуйте все операторы и обрабатывайте как-то неправильные значения.

foo = 100; // works
++foo; // should throw an exception or perform an assert

Используйте повышающие операторы , чтобы помочь вам с перегрузкой операторов.

И, вероятно, было бы хорошо иметь параметр в качестве параметра шаблона: либо исключение, либо утверждение.

Я бы использовал такой класс. Всегда лучше иметь параметр индекса, который автоматически проверяет диапазон векторов и делает утверждение.

void foo( VectorIndex i );
3 голосов
/ 15 апреля 2009

Вам не нужно перегружать все операторы, как предлагали другие, хотя этот подход обеспечивает максимальный контроль, поскольку выражения, включающие объекты типа constrained<T>, останутся этого типа.

Альтернативой может быть только перегрузка мутирующих операторов (=, + =, - =, * =, / =,% =, & =, | =, ^ =, << =, >> =, pre и post ++, pre и post -) и обеспечить пользовательское преобразование в T:

template<typename T>
class constrained {
    ... // As before, plus overloads for all mutating operators
public:
    operator T() const {
        return value;
    }
};

Таким образом, любое выражение, включающее объект constrained<T> (например, x + y, где x - это int, а y - constrained<int>), будет rvalue типа T, который обычно больше удобно и эффективно. Безопасность не теряется, потому что вам не нужно контролировать значение любого выражения , связанного с объектом constrained<T> - вам нужно проверять ограничения только тогда, когда T становится constrained<T>, а именно в конструкторе constrained<T> и в любом из операторов мутации.

2 голосов
/ 15 апреля 2009

Boost.Constrained_Value может представлять интерес для вас. Это было проверено в декабре прошлого года, но это не в последней версии Boost. IIRC, обзор был в основном положительным, но решение еще не принято.

2 голосов
/ 15 апреля 2009

Я согласен с Николаем Голубевым, что операторы буста помогут.

Вы должны определить все операторы, которые вам требуются для всех типов, которые вы используете.

Если какой-либо из используемых вами типов не поддерживает оператор (например, оператор ++ ()), то код, вызывающий этот метод, не будет компилироваться, но все другие использования будут.

Если вы хотите использовать разные реализации для разных типов, используйте специализацию шаблонов.

1 голос
/ 15 апреля 2009

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

0 голосов
/ 15 апреля 2009

Boost на самом деле обсуждал такую ​​библиотеку (я не знаю, что с ней стало). Я также написал свою собственную версию такого типа, с немного другим поведением (менее гибким, но более простым). Я опубликовал в блоге, по общему признанию, несколько предвзятое сравнение: Ограниченные и ограниченные типы значений

Редактировать : очевидно, Эрик лучше знает, что случилось с реализацией boost.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...