constおよびnon-const参照メンバーのC ++クラスのオーバーライド

2020-08-01 c++

そのため、メンバーとしてstd :: byteへの参照と個々のビットのインデックスを格納して、そのビットの値にアクセスし、そのビットに割り当てることを可能にするビットマスククラスを作成しています。渡されたstd :: byteの値がオプションでconstになることも可能にしたいと思います。それがconstである場合は、クラス自体をconstと見なすか、少なくとも、 std :: byteの基礎となる値(割り当てなど)は機能しません。しかし、複雑すぎると考えるコードをコピー貼り付けせずにそれを実装する方法はわかりません。これを回避する簡単な方法はありますか?これは、ビットマスククラスの現在のコードです。

class bitmask
{
    public:
        bitmask(std::byte &chunk, std::uint_fast8_t index) noexcept
            : _chunk(chunk), _index(index){};
        bitmask(bitmask const &source) = default;
        
        operator bool() const noexcept
        {
            return static_cast<bool>((_chunk >> (7 - _index)) & std::byte{1});
        }
        bitmask &operator=(bool val) noexcept
        {
            _chunk = ((_chunk & ~(std::byte{1} << (7 - _index))) |
                      (std::byte{val} << (7 - _index)));
            return *this;
        }

    private:
        std::byte &_chunk;
        std::uint_fast8_t const _index;
};

基本的には、チャンクがconst参照であり、代入演算子が存在しないバリアントを作成することです。既存のコードをコピーして貼り付けないで、繰り返しを避けます。

PS:問題をエレガントに解決する限り、C ++ 20などのC ++標準を使用してもかまいません。

Answers

1つのオプションは、 bitmaskをテンプレートに変換し、SFINAE +タイプの特性を使用して動作を変更することです。

//       vvv defaults to non-const, change if desired
template<typename Chunk = std::byte>
class bitmask
{
    static_assert(std::is_same_v<std::remove_const_t<Chunk>, std::byte>);

    public:
        bitmask(Chunk &chunk, std::uint_fast8_t index) noexcept
            : _chunk(chunk), _index(index){};
        bitmask(bitmask const &source) = default;

        operator bool() const noexcept
        {
            return static_cast<bool>((_chunk >> (7 - _index)) & std::byte{1});
        }

        template<bool Enable = !std::is_const_v<Chunk>, typename = std::enable_if_t<Enable>>
        bitmask &operator=(bool val) noexcept
        {
            _chunk = ((_chunk & ~(std::byte{1} << (7 - _index))) |
                    (std::byte{val} << (7 - _index)));
            return *this;
        }

    private:
        Chunk &_chunk;
        std::uint_fast8_t const _index;
};

C ++ 17以降を使用する場合、 クラステンプレート引数の推定はbitmaskのコンストラクターに渡された引数に基づいてChunkを推測するため、 テンプレート引数を手動で指定する必要はありません。以前のバージョンのC ++は、 make_bitmaskファクトリ+タイプエイリアスを使用して同様の美学を実現できますが、残念ながらconstとnon-constのバリアントは必ずしも異なるスペルで記述する必要があります。

これは、ポインタが許可するものです。完全に一定または完全に可変。したがって、常に真偽のステートメントを作成できます。
定数かそうでないかを推定するテンプレートクラス。

template<class T>
class overload {

    public:
    overload(T t): t(t) {

    }
    ~overload() {}
    T get() {

            if(std::is_const<T>::value)
                    clog <<"const\t " <<t <<endl;
            else if(! std::is_const<T>::value)
                    clog <<"variable\t " <<t <<endl;
                    
            return this->t;
    }       
    T set(T t) {
            this->t= t;
    }

    private:
    T t;

};

class test {

    public:
    test(const int * const _t) : _t(_t) {}
    test(int *t) : t(t), _t(NULL) {}
    ~test() {}

    int get() { return *(this->t); }
    void set(int *t) { this->t= t; }
    const int * const _get() { return (this->_t); }

    int __get( ) {
            return (_t==NULL)?*t:*_t;
    }
    //void _set(const int * const _t) { this->_t= _t; }     
    private:
    int *t;
    const int *const _t;
};

int main(int argc, char*argv[]) {
    int n;
    const int m= 99;
    
    n= 100;
    overload<int> o(n);
    overload<const int> _o(m);

    ::cout <<o.get() <<endl;
    ::cout <<_o.get() <<endl;        

    test t(&n), _t(&m);

    ::cout <<t.get() <<"\t" <<*_t._get() <<"\t" <<t.__get() <<"\t" <<_t.__get() <<endl;
    return 0;
}

したがって、ここには本当に良い答えがいくつかありましたが、特にエレガントなものは見つからなかったので、さらに深く掘り下げて自分の問題を解決することにしました。この解決策は完全に自分のものではなく、@ ildjarnの回答に触発されたことに注意してください。

これは私が私の問題を解決した方法です

// Class to mask reference to individual bit
template <bool is_const = false>
class bitmask
{
  public:
    using ChunkType = std::conditional_t<is_const, std::byte const, std::byte>;

    bitmask(ChunkType &chunk, std::uint_fast8_t index) noexcept
        : _chunk(chunk), _index(index){};
    bitmask(bitmask const &source) = default;

    operator bool() const noexcept
    {
        return static_cast<bool>((_chunk >> (7 - _index)) & std::byte{1});
    }

    template <typename = std::enable_if_t<!is_const>>
    bitmask &operator=(bool val) noexcept
    {
        _chunk = ((_chunk & ~(std::byte{1} << (7 - _index))) |
                  (std::byte{val} << (7 - _index)));
        return *this;
    }

  private:
    ChunkType &_chunk;
    std::uint_fast8_t const _index;
};

bitmask(std::byte &, std::uint_fast8_t)->bitmask<false>;
bitmask(std::byte const &, std::uint_fast8_t)->bitmask<true>;

つまり、基本的に、クラスはテンプレートであり、参照されるバイトがconstであるかどうかに応じてブール値を取得します。また、コンストラクターにテンプレート引数の推定ヒントを追加して、constnessが自動的に推定されるようにしました。また、 operator=is_constfalse場合にのみ機能するようにしis_const false

Related