使用和接受具有重载方法和运算符的不同大小的文字 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;
}
所以我有了这个测试用例,并试图不必进行一百万次运算符重载或处理重载冲突或复杂性。我希望能够使用运算符重载处理文字数组常量。这是为预期库创建易用性的一种要求(此测试用例朝相同的方向射击。)
我正在寻找能够添加、减去可变长度 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;
}