2^x-Flags "objektorientiert" simulieren



  • Halli hallo!
    Und zwar stellte sich mir die Frage, ob es irgendeine nette und prägnante Art und Weise gibt, die 2^x-Flags, die man aus C so kennt vernünftig und "Typsicher" in C++ rüberzuretten und dabei die "Beschränkung" (Die man aber sowieso fast niemals erreicht bzw. natürlich umschiffen kann) auf die Anzahl von Flags aufzuweichen.

    Ich habe mich mal daran versucht, aber wie ihr seht, kommt dabei ein Kauderwelsch raus. Ich frage mich, ob es eine total elegante Lösung dafür gibt.
    Am Ende dann mein "Pseudo"-Source.

    Viele Grüße,
    Michael

    #include <bitset>
    #include <iostream>
    
    struct null;
    
    template< int in1, int in2 >
    struct ct_max {
    	static const int max_ = (in1 > in2) ? in1 : in2;
    };
    
    template< class base >
    struct counter {
        static const int count_ = base::count_ + 1;
    };
    
    template< >
    struct counter< null > {
    	static const int count_ = 0;
    };
    
    template< class last_counter, class context >
    class flag_base
    {
    public:
    	typedef context context_;
    	typedef counter< last_counter > counter_;
    	typedef flag_base< counter_, context > next_;
    };
    
    template< unsigned int count, class context_ >
    struct flag_set
    {
    	void set( unsigned int which ) {
    		flags_.set( which );
    	}
    
    	bool test( unsigned int which ) const {
    		return which < flags_.size() && flags_.test( which );
    	}
    
    	template< unsigned int count2 >
    	flag_set& operator=( const flag_set< count2, context_ >& f ) {
    		flags_.reset();
    		for( unsigned int i=0; i<f.size_; ++i ) {
    			flags_[i] = f.test(i);
    		}
    		return *this;
    	}
    
        friend std::ostream& operator<<( std::ostream& o, const flag_set< count, context_ >& fs )
        {
    		o << fs.flags_;
    		return o;
        }
    
    	static const int size_ = count;
    
    private:
    	std::bitset< count > flags_;
    };
    
    template< class U, class V, class context > 
    flag_set< ct_max< flag_base<U,context>::counter_::count_, flag_base<V,context>::counter_::count_ >::max_+1, context >
    operator|( const flag_base<U, context>& f1, const flag_base<V, context>& f2 )
    {
    	flag_set< ct_max< flag_base<U,context>::counter_::count_, flag_base<V,context>::counter_::count_ >::max_+1, context > temp;
    	temp.set( flag_base<U,context>::counter_::count_ );
    	temp.set( flag_base<V,context>::counter_::count_ );
    
    	return temp;
    }
    
    template< unsigned int U, class V, class context >
    flag_set< ct_max< flag_set<U,context>::size_, flag_base<V,context>::counter_::count_+1 >::max_, context >
    operator|( const flag_set< U,context >& f1, const flag_base<V,context>& f2 ) {
        flag_set< ct_max< flag_set<U,context>::size_, flag_base<V,context>::counter_::count_+1 >::max_, context > temp;
        temp = f1;
        temp.set( flag_base<V, context>::counter_::count_ );
        return temp;
    }
    
    template< unsigned int U, class V, class context >
    bool operator&( const flag_set<U,context>& f1, const flag_base<V,context>& f2 ) {
    	return f1.test( flag_base<V,context>::counter_::count_ );
    }
    
    struct myflags1 {};
    class flag1_ : public flag_base< null, myflags1 > {}  flag1;
    class flag2_ : public flag1_::next_ {}  flag2;
    class flag3_ : public flag2_::next_ {}  flag3;
    class flag4_ : public flag3_::next_ {}  flag4;
    
    struct myflags2 {};
    class flag_1 : public flag_base< null, myflags2 > {} flag1_1;
    
    int main(int argc, char* argv[])
    {
    	std::cout << ((flag1|flag2|flag3)&flag4) << std::endl;
    	std::cout << sizeof( flag4 );
    
    	// std::cout << (flag1|flag2)&flag1_1 << std::endl;
    	return 0;
    }
    


  • Wäre da nicht std::bitset eine Möglichkeit? Oder was versuchst du genau?


Log in to reply