简体   繁体   English

如何使用命名的公共成员(即x,y,z,…)创建大小可变的C ++数组?

[英]How to create variable sized C++ array with named public members i.e. x, y, z, …?

I am looking for a way to create a general std-like std::array< T, N > which has named member elements ie, x, y, z, ... 我正在寻找一种创建类似于std::array< T, N >的常规std的方法,该方法已命名成员元素,即x,y,z,...

Is there a way to use variadic templates to construct such an object, so that the members are conditionally defined via a template parameter? 有没有一种方法可以使用可变参数模板来构造这样的对象,以便通过模板参数有条件地定义成员?

It is absolutely vital that the object has array-like access via the operator[] , and also that its memory footprint is not bloated by extra references or pointers. 绝对重要的是,对象可以通过operator[]进行类似数组的访问,并且其内存占用量不会因多余的引用或指针而膨胀。

I have considered mimicking TR1 traits, but I am really at a loss as to how to begin. 我曾经考虑过模仿TR1特质,但是我真的对如何开始感到迷茫。

There is nothing nice to achieve it: 没有什么好实现的:

#include <cstddef>

template <std::size_t Extent>
struct Tuple;

// You cant not use a template for declaring member names.
// Hence a set of pre-declared tuples.

template <> struct Tuple<1> {
    double x;
    double operator [] (std::size_t idx) const { return x; }
};

template <> struct Tuple<2> {
    double x;
    double y;
    double operator [] (std::size_t idx) const { return (idx < 1) ? x : y; }
};

template <> struct Tuple<3> {
    double x;
    double y;
    double z;
    double operator [] (std::size_t idx) const {
        return (idx < 1)
            ? x
            : (idx < 2)
                ? y
                : z;
    }
};

// However, you pay the price of conditional evaluation for accessing
// the members via operator [].

// An alternative is accessing the values through a std::array and member functions:

template <> struct Tuple<1> {
    std::array<double, 1> data;
    double x() const { return data[0]; }
    double operator [] (std::size_t) const { return data[0]; }
};

template <> struct Tuple<2> {
    std::array<double, 2> data;
    double x() const { return data[0]; }
    double y() const { return data[1]; }
    double operator [] (std::size_t idx) const { return data[idx]; }
};

template <> struct Tuple<3> {
    std::array<double, 3> data;
    double x() const { return data[0]; }
    double y() const { return data[1]; }
    double z() const { return data[2]; }
    double operator [] (std::size_t idx) const { return data[idx]; }
};

// However, now you have to write tuple.x(), which is annoying
// in mathematical equations.

For completeness: Another option is type punning through a union. 为了完整起见:另一个选择是通过联合键入类型。 But that is a move to the dark side of undefined behavior (See: Opinions on type-punning in C++? ). 但这是向未定义行为的阴暗面迈进的一步(请参阅: 关于C ++中类型处理的观点? )。

I am going to answer my own question after playing around for some time. 我玩了一段时间后要回答自己的问题。 I think I have found what I am looking for although this is just a rough sketch. 我想我已经找到了我想要的东西,尽管这只是一个粗略的草图。 I will post this, in case others are curious about similar problems. 如果其他人对类似问题感到好奇,我将发布此消息。

Definition: Tuple.hpp 定义: Tuple.hpp

#include <cassert>
#include <iostream>

namespace details
{

    template<bool>
    struct rule_is_greater_than_4;

    template<>
    struct rule_is_greater_than_4<true> {};

    template<>
    struct rule_is_greater_than_4<false> {};

    template<class T, size_t N, size_t M>
    class inner_storage : rule_is_greater_than_4< ( M > 4 )>
    {

    public:

        T x, y, z, w;

    private:

        T more_data[ N - 4 ];

    };

    template<class T, size_t N>
    class inner_storage<T, 2, N>
    {

    public:

        T x, y;

    };

    template<class T, size_t N>
    class inner_storage<T, 3, N>
    {

    public:

        T x, y, z;
    };

    template<class T, size_t N>
    class inner_storage<T, 4, N>
    {

    public:

        T x, y, z, w;

    };

}

template<class T, size_t N>
class Tuple : public details::inner_storage<T, N, N>
{

public:

    static_assert( N > 1, "Size of 'n-tuple' must be > 1." );



    // -- Constructors --

    Tuple();

    Tuple( T k );

    Tuple( T x, T y );

    Tuple( T x, T y, T z );

    Tuple( T x, T y, T z, T w );

    // -- Access operators --

    const size_t size();

    T &operator[]( const size_t i );
    T const &operator[]( const size_t i ) const;

    // -- Unary arithmetic operators --

    Tuple<T, N> &operator=( Tuple<T, N> const &t );

    friend std::ostream &operator<<( std::ostream &os, Tuple<T, N> &t );

};

// -- Unary operators --

template<class T, size_t N>
Tuple<T, N> operator+( Tuple<T, N> const &t );

template<class T, size_t N>
Tuple<T, N> operator-( Tuple<T, N> const &t );

// -- Binary arithmetic operators --

template<class T, size_t N>
Tuple<T, N> operator+( Tuple<T, N> const &t1, Tuple<T, N> const &t2 );

template<class T, size_t N>
Tuple<T, N> operator-( Tuple<T, N> const &t1, Tuple<T, N> const &t2 );

template<class T, size_t N>
Tuple<T, N> operator*( T const &s, Tuple<T, N> const &t2 );

template<class T, size_t N>
Tuple<T, N> operator*( Tuple<T, N> const &t1, T const &s );

template<class T, size_t N>
Tuple<T, N> operator/( Tuple<T, N> &t1, T const &s );

// -- Boolean operators --

template<class T, size_t N>
bool operator==( Tuple<T, N> const &t1, Tuple<T, N> const &t2 );

template<class T, size_t N>
bool operator!=( Tuple<T, N> const &t1, Tuple<T, N> const &t2 );

// -- Stream operator --

template<class T, size_t N>
inline std::ostream &operator<<( std::ostream &os, Tuple<T, N> const &t );

#include "Tuple.inl"

Implementation: Tuple.inl 实施: Tuple.inl

// -- Constructors --

template <class T, size_t N>
Tuple<T, N>::Tuple()
{

}

template <class T, size_t N>
Tuple<T, N>::Tuple( T k )
{

    for( size_t i = 0; i < N; i++ )
    {

        operator[]( i ) = k;

    }

}

template <class T, size_t N>
Tuple<T, N>::Tuple( T x, T y )
{

    static_assert( N == 2, "This constructor is resererved for 2-tuples." );

    this->x = x;
    this->y = y;

}

template <class T, size_t N>
Tuple<T, N>::Tuple( T x, T y, T z )
{

    static_assert( N == 3, "This constructor is resererved for 3-tuples." );

    this->x = x;
    this->y = y;
    this->z = z;

}

template <class T, size_t N>
Tuple<T, N>::Tuple( T x, T y, T z, T w )
{

    static_assert( N == 4, "This constructor is resererved for 4-tuples." );

    this->x = x;
    this->y = y;
    this->z = z;
    this->w = w;

}

// -- Access operators --

template <class T, size_t N>
const size_t Tuple<T, N>::size()
{

    return N;

}

template <class T, size_t N>
T &Tuple<T, N>::operator[]( const size_t i )
{

    assert( i < N );

    return ( &( this->x ) )[ i ];

}

template <class T, size_t N>
T const &Tuple<T, N>::operator[]( const size_t i ) const
{

    assert( i < N );

    return ( &( this->x ) )[ i ];

}

// -- Unary arithmetic operators --

template<class T, size_t N>
Tuple<T, N> &Tuple<T, N>::operator=( Tuple<T, N> const &t )
{

    for( size_t i = 0; i < size(); i++ )
    {

        this->operator[]( i ) = t[ i ];

    }

    return *this;

}

// -- Unary operators --

template<class T, size_t N>
Tuple<T, N> operator+( Tuple<T, N> const &t )
{

    return t;

}

template<class T, size_t N>
Tuple<T, N> operator-( Tuple<T, N> const &t )
{

    return t * T( 0.0f );

}

// -- Binary operators --

template<class T, size_t N>
Tuple<T, N> operator+( Tuple<T, N> const &t1, Tuple<T, N> const &t2 )
{

    Tuple<T, N> sum;

    for( size_t i = 0; i < N; i++ )
    {

        sum[ i ] = t1[ i ] + t2[ i ];

    }

    return sum;

}

template<class T, size_t N>
Tuple<T, N> operator-( Tuple<T, N> const &t1, Tuple<T, N> const &t2 )
{

    Tuple<T, N> difference;

    for( size_t i = 0; i < N; i++ )
    {

        difference[ i ] = t1[ i ] - t2[ i ];

    }

    return difference;

}

template<class T, size_t N>
Tuple<T, N> operator*( Tuple<T, N> const &t, T const &s )
{

    Tuple<T, N> product;

    for( size_t i = 0; i < N; i++ )
    {

        product[ i ] = t[ i ] * s;

    }

    return product;

}

template<class T, size_t N>
Tuple<T, N> operator*( T const &s, Tuple<T, N> const &t )
{

    Tuple<T, N> product;

    for( size_t i = 0; i < N; i++ )
    {

        product[ i ] = s * t[ i ];

    }

    return product;

}

template<class T, size_t N>
Tuple<T, N> operator/( Tuple<T, N> const &t, T const &s )
{

    assert( s != T( 0.0f ) );

    Tuple<T, N> quotient;

    T denom = T( 1.0f ) / s;

    for( size_t i = 0; i < N; i++ )
    {

        quotient[ i ] = t[ i ] * denom;

    }

    return quotient;

}

// -- Boolean operators --

template<class T, size_t N>
bool operator==( Tuple<T, N> const &t1, Tuple<T, N> const &t2 )
{

    bool equal = true;

    for( size_t i = 0; i < N; i++ )
    {

        equal = ( t1[ i ] == t2[ i ] ) ? equal : false;

    }

    return equal;

}

template<class T, size_t N>
bool operator!=( Tuple<T, N> const &t1, Tuple<T, N> const &t2 )
{

    return !( t1 == t2 );

}

// -- Stream operator --

template <class T, size_t N>
inline std::ostream &operator<<( std::ostream &os, Tuple<T, N> const &t )
{

    os << "( ";

    for( size_t i = 0; i < t.size(); i++ )
    {

        os << t[ i ];

        if( i < t.size() - 1 )
        {

            os << ", ";

        }

    }

    os << " )";

    return os;

}

I'm not sure if all the operator overloads are covered, but I wanted to be brief. 我不确定是否涵盖了所有运算符重载,但我想简短一点。 I'm also not happy with the way the constructors are created (maybe variadic templates could come to the rescue). 我对构造函数的创建方式也不满意(也许可变参数模板可以解决)。 At least it gives me following desirable functionality: 至少它为我提供了以下理想的功能:

typedef Tuple<float, 2> Vec2;
typedef Tuple<float, 4> Vec4;
typedef Tuple<float, 10> Vec10;

Vec2 a( 1.0 );

a.x = 3.0f;
a.y = -3.0f;

assert( a[ 1 ] == -3.0f ); // this works

// a.z = 1.0f; ------> compiler error

Vec10 b;

b.x = 0.0f; b.y = 1.0f; b.z = 2.0f; b.w = 3.0f;

b[ 5 ] = 12.0f;

// etc...

Say you want to store types of int 假设您要存储int类型

using mytype = int;
struct mytuple_ {
  mytype x;
  mytype y;
  mytype z;
} tup;

This meets your criteria of not adding any extra memory usage and simply lays out the data in memory. 这符合您不增加任何额外内存使用量的条件,并且仅对内存中的数据进行布局。

To say set x=5 要说设置x = 5

tup.x = 5;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM