使用和接受具有重载方法和运算符的不同大小的文字 carray 常量的优雅或至少可行的方法

A graceful or at least workable way of using and accepting literal carray constants of varying size with overloaded methods and operators

所以我有了这个测试用例,并试图不必进行一百万次运算符重载或处理重载冲突或复杂性。我希望能够使用运算符重载处理文字数组常量。这是为预期库创建易用性的一种要求(此测试用例朝相同的方向射击。)

我正在寻找能够添加、减去可变长度 carray 文字常量的解决方案。我有几个解决方案,其中一个可行,但前提是 C_COORDS 和 N_COORDS 都不止一个。我正在使用定义而不是模板来简化测试用例,但这些定义将在最后一个小时被模板替换。

欢迎提出任何建议。请注意,我确定我可以更清楚地说明这一点,但目前看不出如何。 30 年前,我曾经做过很多 C 编程。但从那以后就没怎么接触过 CPP,是的,我主要了解 CPP 以及它与旧 C 之间的区别,但还没有太多经验。我只是注意到因为我确定我错过了一些明显的事情。谢谢。我的测试用例如下....

/** Coord.cpp */

#include <iostream>
#include <cstring>
#include <initializer_list>
#include <cassert> 


#define T_COORDS float    // the type of coordinates
#define N_COORDS (2)      // the coordinates per item
#define C_COORDS (2)      // the number of coordinate items
#define L_COORDS (N_COORDS*C_COORDS)      // the number of coordinate items

using namespace std;


class Coords {
public:
  T_COORDS coords[L_COORDS];
  Coords()
  {
    memset(this->coords, 0, sizeof(Coords));
  }
  Coords(const T_COORDS inits[L_COORDS])
  {
    memmove(this->coords, &inits, sizeof(Coords));
  }
  Coords(initializer_list<T_COORDS> inits) : coords{}
  {
    copy( inits.begin(), next( inits.begin(), L_COORDS ), coords );
  }
  friend Coords operator + (const Coords &coords0, const Coords &coords1) 
  {
    Coords result = coords0;
    for (int i=0; i < L_COORDS; i++)
        result.coords[i] += coords1.coords[i];
    return result;
  }
  /* original that complains about taking size from a temporary array.  the next 
   * 2 UNCOMMENTED overloads accept a fixed length array, but then I have to 
   * have for every case and they cannot overlap.
  friend Coords operator + (const Coords& coords0, const T_COORDS (& coords1)[])
  {
    int n = sizeof(coords1) / sizeof(T_COORDS);
    if ( ! n || n > L_COORDS || n % N_COORDS )
        throw "coordinate count must be a multiple and at least N_COORDS and not more then T_COORDS";
    cout << "n = " << n << endl;
    Coords result = coords0;
    for (int i=0; i < L_COORDS; i++)
        result.coords[i] += coords1[i%n];
    return result;
  }
  */
  /* bad solution was to make to overloads that match of a fixed length array, 
   * however it sucks because if N_COORDS is 1, then it also won't compile 
   * because it ends up with duplicate overloads as L_COORDS is equal to 
   * C_COORDS when N_COORDS is one, and same is true is C_COORDS is one.  
   * WHat I hope for is a way to accept any array or at least any array with a 
   * length >= and on boundaries of C_COORDS and not more the L_COORDS */
  friend Coords operator + (const Coords& coords0, const T_COORDS (& coords1)[C_COORDS])
  {
    int n = sizeof(coords1) / sizeof(T_COORDS);
    if ( ! n || n > L_COORDS || n % N_COORDS )
        throw "coordinate count must be a multiple and at least N_COORDS and not more then T_COORDS";
    cout << "n = " << n << endl;
    Coords result = coords0;
    for (int i=0; i < L_COORDS; i++)
        result.coords[i] += coords1[i%n];
    return result;
  }
  /* as above, so below but for different size array */
  friend Coords operator + (const Coords& coords0, const T_COORDS (& coords1)[L_COORDS])
  {
    int n = sizeof(coords1) / sizeof(T_COORDS);
    if ( ! n || n > L_COORDS || n % N_COORDS )
        throw "coordinate count must be a multiple and at least N_COORDS and not more then T_COORDS";
    cout << "n = " << n << endl;
    Coords result = coords0;
    for (int i=0; i < L_COORDS; i++)
        result.coords[i] += coords1[i%n];
    return result;
  }
};


void print_coords(const char* label, Coords coords)
{
  cout << label << ": ( " << coords.coords[0];
  for (int i=1; i < L_COORDS; i++) {
    cout << ", " << coords.coords[i];
  }
  cout << " }" << endl;
};


int main () {

  Coords coords0;

  print_coords("coords0", coords0);

  Coords coords1 {4,5,6,7};
  print_coords("coords1", coords1);

  Coords coords2 {8,9,10,11};
  print_coords("coords2", coords2);

  Coords coords3 = coords1 + coords2;
  print_coords("coords3", coords3);

  T_COORDS tmp[] = {-2,-2,-2,-2};
  Coords coords4 = coords3 + tmp;
  print_coords("coords4", coords4);

  T_COORDS tmp2[] = {-2,-2};
  Coords coords5 = coords4 + tmp2;
  print_coords("coords5", coords5);

  Coords coords6 = coords5 + (T_COORDS[]){10,20,30,40};
  print_coords("coords6", coords6);

  Coords coords7 = coords6 + (T_COORDS[]){10,20};
  print_coords("coords7", coords7);

  /* this won't compile with fixes length overloads because it don't match and thats ok.
  try {
    Coords coords8 = coords7 + (T_COORDS[]){10,20,30};
    print_coords("coords8", coords8);
  } catch (const char* msg) {
    cout << "threw exception on 3 coordinates as expected" << endl;
  }
  */
  cout << "Done!" << endl;
  return 0;
}


/**
 * g++ Coord.cpp -o coord
 * ./coord
 * RESULING OUTPUT:
 *  coords0: ( 0, 0, 0, 0 }
 *  coords1: ( 4, 5, 6, 7 }
 *  coords2: ( 8, 9, 10, 11 }
 *  coords3: ( 12, 14, 16, 18 }
 *  n = 4
 *  coords4: ( 10, 12, 14, 16 }
 *  n = 2
 *  coords5: ( 8, 10, 12, 14 }
 *  n = 4
 *  coords6: ( 18, 30, 42, 54 }
 *  n = 2
 *  coords7: ( 28, 50, 52, 74 }
 *  Done!
*/

const T_COORDS (& coords1)[] 是未知边界的数组。你知道尺寸,所以这不是你想要的。

您可能会使用模板:

template <std::size_t N>
            // SFINAE, instead of throw
            // care, then Coords+Coords is viable and no exception in Coords(initializer_list)
            // For invalid size
            /*, std::enable_if_t<N != 0 && N <= L_COORDS && N % N_COORDS == 0, bool> = false*/>
friend Coords operator + (const Coords& coords0, const T_COORDS (& coords1)[N])
{
    if ( ! N || N > L_COORDS || N % N_COORDS )
        throw "coordinate count must be a multiple and at least N_COORDS and not more then T_COORDS";
    std::cout << "n = " << N << std::endl;
    Coords result = coords0;
    for (int i=0; i < L_COORDS; i++)
        result.coords[i] += coords1[i%N];
    return result;
}

Demo