Изящный или, по крайней мере, работоспособный способ использования и принятия буквальных констант переноса различного размера с перегруженными методами и операторами. - PullRequest
0 голосов
/ 28 мая 2020

Итак, у меня есть этот тестовый пример, и я пытаюсь избавиться от необходимости делать миллион перегрузок операторов или обрабатывать конфликты перегрузки или сложности. Я хочу иметь возможность обрабатывать константы литерального массива с перегрузками операторов. Это своего рода требование для упрощения использования предполагаемой библиотеки (этот тестовый пример направлен в том же направлении). . У меня есть несколько решений, одно из которых работает, но только если C_COORDS и N_COORDS больше одного. Я использую определения вместо шаблонов, чтобы упростить тестовый пример, но в последний час эти определения будут заменены шаблонами.

Любые предложения приветствуются. Заметьте, я уверен, что смогу прояснить это, но пока не понимаю, как это сделать. Я часто занимаюсь программированием C 30 лет go. Но с тех пор особо не трогал 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!
*/

1 Ответ

0 голосов
/ 28 мая 2020

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

Демо

...