一个优雅的或至少是可行的方式来使用和接受不同大小的字面carray常量与重载方法和操作符。

问题描述 投票:0回答:1

所以,我有这个测试用例,并试图不用做一百万个操作符重载或处理重载碰撞或复杂性。 我希望能够用操作符重载来处理数组常量的文字。 这也是一种要求,以创造出易于使用的库(这个测试用例也是朝这个方向发展的)。

我正在寻找一个能够添加、减少可变长度carray字面常量的解决方案。 我有几个解决方案,其中一个可行,但只有当C_COORDS和N_COORDS都超过一个时才行。 我是用defines代替Template来简化测试用例,但是这些defines在最后的时候会被Template代替。

有什么建议欢迎提出来。 注意,我相信我可以把这个问题说得更清楚,但目前看不出怎么说。 30年前我曾经做过很多C语言编程。 但之后就没怎么接触过CPP了,是的,我主要了解CPP,也了解它和老C的区别,但还没什么经验。我只是注意一下,因为我确信我漏掉了一些obvious的东西。 谢谢。 我的测试用例如下....

/** 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!
*/
c++ constants dynamic-arrays variable-length-array overloaded-lists
1个回答
0
投票

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;
}

演示

© www.soinside.com 2019 - 2024. All rights reserved.