在C ++中实现变量约束

时间:2009-04-15 10:26:48

标签: c++ constraints

我一直在寻找一个示例,展示如何在C ++中实现约束(或者是一个可以让我轻松完成此操作的boost库),但没有太多运气。我能想到的最好的是:

#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 个答案:

答案 0 :(得分:4)

看起来很好的例子。但是一定要实现所有的操作符并处理错误的值。

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

使用boost operators帮助您解决操作员过载问题。

最好有一个选项作为模板参数:异常或断言。

我会用这样的课。拥有一个自动检查矢量范围并进行断言的索引参数总是更好。

void foo( VectorIndex i );

答案 1 :(得分:3)

您不需要像其他人建议的那样重载所有运算符,尽管这是提供最大控制的方法,因为涉及constrained<T>类型的对象的表达式将保留此类型。

另一种方法是仅重载变异运算符(=,+ =, - =,* =,/ =,%=,&amp; =,| =,^ =,&lt;&lt; =,&gt;&gt; =,前后++,前后 - )并提供用户定义的转换T

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

这样,任何涉及constrained<T>对象的表达式(例如x + y xintyconstrained<int>)都将是类型T的右值,通常更方便有效。没有安全性丢失,因为您不需要控制涉及constrained<T>对象的任何表达式的值 - 您只需要在{{1}时检查约束变成T,即在constrained<T>的构造函数和任何变异运算符中。

答案 2 :(得分:2)

我同意Mykola Golubyev的观点,即提升运营商会有所帮助。

您应该为您正在使用的所有类型定义所需的所有运算符。

如果您使用的任何类型不支持运算符(例如运算符++()),则调用此方法的代码将无法编译,但所有其他用法都将编译。

如果要对不同类型使用不同的实现,请使用模板专业化。

答案 3 :(得分:2)

Boost.Constrained_Value可能对您有用。去年12月是reviewed,但它不是最新的Boost版本。 IIRC,审查大多是积极的,但该决定仍未决定。

答案 4 :(得分:1)

我可能只是感到困惑,但是如果你面对必须违反特定约束的参数,那么为它们创建一个类是不是最容易的,检查构造函数和赋值运算符中的约束?

答案 5 :(得分:0)

Boost实际上正在讨论这样一个库(我不知道它变成了什么)。我也编写了我自己的这种类型的版本,行为略有不同(灵活性较差,但更简单)。我在博客中发表了一个公认有点偏见的比较:Constrained vs. restricted value types

编辑:显然Eric更了解促进实施的进展情况。