我正在构建自己的具有多个新功能支持和运算符的Array实现。我researched a lot打算扩展std::array
,最后,它引起了很多问题,因此我决定使用组合代替继承。
接下来,我们可以看到我的Array
自定义实现的一小部分,其中包括模板元编程。在此简单版本上,有一种std::ostream
的打印方法和一个简单的operator/
定义:
#include <array>
#include <iostream>
template <unsigned int array_width, typename DataType, typename DerivedType>
struct Array {
std::array<DataType, array_width> _data;
Array() {
for(int index = 0; index < array_width; ++index) _data[index] = 1;
}
DerivedType operator/(const double& data) {
unsigned int column;
DerivedType new_array;
for(column = 0; column < array_width; column++) {
new_array._data[column] = _data[column] / data;
}
return new_array;
}
friend std::ostream& operator<<( std::ostream &output, const Array &array ) {
unsigned int column; output << "(";
for( column=0; column < array_width; column++ ) {
output << array._data[column];
if( column != array_width-1 ) {
output << ", ";
}
}
output << ")"; return output;
}
};
struct Coordinate : public Array<3, double, Coordinate> {
typedef Array< 3, double, Coordinate > SuperClass;
double& x;
double& y;
double& z;
Coordinate() : SuperClass{}, x{this->_data[0]}, y{this->_data[1]}, z{this->_data[2]} {}
};
int main() {
Coordinate coordinate;
std::cout << "coordinate: " << coordinate << std::endl;
Coordinate new_coordinate = coordinate / 10.0;
std::cout << "new_coordinate: " << new_coordinate << std::endl;
}
但是,此实现使用Curiously Recurring Template Pattern有一个限制。我找不到直接实例化基类Array
的数组的方法。例如,如果我尝试以下操作:
int main() {
Array<5, int> int_array;
std::cout << "int_array: " << int_array << std::endl;
Array<5, int> new_int_array = int_array / 10;
std::cout << "new_int_array: " << new_int_array << std::endl;
}
编译器说:
test.cpp: In function 'int main()':
test.cpp:45:15: error: wrong number of template arguments (2, should be 3)
Array<5, int> int_array;
^
test.cpp:6:8: note: provided for 'template<unsigned int array_width, class DataType, class DerivedType> struct Array'
struct Array {
^~~~~
test.cpp:48:15: error: wrong number of template arguments (2, should be 3)
Array<5, int> new_int_array = int_array / 10;
^
test.cpp:6:8: note: provided for 'template<unsigned int array_width, class DataType, class DerivedType> struct Array'
struct Array {
^~~~~
然后,我尝试将自己的模板类作为struct Array
声明的默认参数传递,如下所示:
template <unsigned int array_width, typename DataType, typename DerivedType>
struct Array;
template <unsigned int array_width, typename DataType, typename DerivedType=Array>
struct Array {
std::array<DataType, array_width> _data;
// ...
但是,我发现编译器似乎不允许将模板类传递给另一个模板类,因为如果未实例化它们,它们将无法定义类型。
test.cpp:8:77: error: invalid use of template-name 'Array' without an argument list
template <unsigned int array_width, typename DataType, typename DerivedType=Array>
^~~~~
test.cpp:8:77: note: class template argument deduction is only available with -std=c++1z or -std=gnu++1z
test.cpp:6:8: note: 'template<unsigned int array_width, class DataType, class DerivedType> struct Array' declared here
struct Array;
^~~~~
test.cpp: In function 'int main()':
test.cpp:48:15: error: template argument 3 is invalid
Array<5, int> int_array;
^
test.cpp:51:15: error: template argument 3 is invalid
Array<5, int> new_int_array = int_array / 10;
因此,这似乎是一个悖论,因为我无法在不事先知道我的完整定义的情况下实例化自己。然后,我尝试创建一个名为ConcreteArray
的虚拟类型,如下所示:
struct ConcreteArray
{
};
template <unsigned int array_width, typename DataType, typename DerivedType=ConcreteArray>
struct Array {
std::array<DataType, array_width> _data;
// ...
但是,这在直接实例化Array
类时会产生问题,因为实现的运算符将返回的类型划分为operator/
并不正确地实例化为派生类类型:
test.cpp: In function 'int main()':
test.cpp:52:43: error: conversion from 'ConcreteArray' to non-scalar type 'Array<5, int>' requested
Array<5, int> new_int_array = int_array / 10;
~~~~~~~~~~^~~~
test.cpp: In instantiation of 'DerivedType Array<array_width, DataType, DerivedType>::operator/(const double&) [with unsigned int array_width = 5; DataType = int; DerivedType = ConcreteArray]':
test.cpp:52:45: required from here
test.cpp:22:17: error: 'struct ConcreteArray' has no member named '_data'
new_array._data[column] = _data[column] / data;
~~~~~~~~~~^~~~~
使用好奇重复模板模式时如何实例化基类?
参考文献:
答案 0 :(得分:2)
在某些情况下,使用DB::table('stock')->join('features',function($join){
$join->on('features.id','=','stock.feature_id')
->where('code', $v);
})
->select('') <--- also select columns here..
->get();
作为Array
是不对称的,而在其他情况下使用实际派生类型,就像您在答案中所介绍的那样。
我想提出一个使用不同方法的解决方案。如果不存在“派生类型”,则使用“空派生类型”。
DerivedType
输出:
#include <iostream>
#include <array>
template <unsigned int array_width, typename DataType>
struct empty_derived_type;
template
<
unsigned int array_width,
typename DataType,
typename DerivedType = empty_derived_type<array_width, DataType>
>
struct Array {
std::array<DataType, array_width> _data;
Array() {
for(unsigned int index = 0; index < array_width; ++index) _data[index] = 1;
}
DerivedType operator/(const double& data) {
unsigned int column;
DerivedType new_array;
for(column = 0; column < array_width; column++) {
new_array._data[column] = _data[column] / data;
}
return new_array;
}
friend std::ostream& operator<<( std::ostream &output, const Array &array ) {
unsigned int column; output << "(";
for( column=0; column < array_width; column++ ) {
output << array._data[column];
if( column != array_width-1 ) {
output << ", ";
}
}
output << ")"; return output;
}
};
template <unsigned int array_width, typename DataType>
struct empty_derived_type : public Array
<
array_width,
DataType,
empty_derived_type<array_width, DataType>
>
{
};
struct Coordinate : public Array<3, double, Coordinate> {
typedef Array< 3, double, Coordinate > SuperClass;
double& x;
double& y;
double& z;
Coordinate() : SuperClass{}, x{this->_data[0]}, y{this->_data[1]}, z{this->_data[2]} {}
};
int main() {
Coordinate coordinate;
std::cout << "coordinate: " << coordinate << std::endl;
Coordinate new_coordinate = coordinate / 10.0;
std::cout << "new_coordinate: " << new_coordinate << std::endl;
Array<5, int> int_array;
std::cout << "int_array: " << int_array << std::endl;
Array<5, int> new_int_array = int_array / 10;
std::cout << "new_int_array: " << new_int_array << std::endl;
}
答案 1 :(得分:-1)
我通过默认将基类派生类参数设置为void来进行管理,然后,当类型为void时,如果将void类型切换/重新定义为当前基类类型,则使用模板/元编程。之所以可行,是因为就像我已经在类中一样,类定义已完成,然后,我们可以使用自己的定义,该定义现在已完成。
这是一个完整的最小工作示例:
#include <array>
#include <iostream>
template<typename condition, typename Then, typename Else>
struct ARRAY_DEFAULT_IF_TYPE {
typedef Else Result;
};
template<typename Then, typename Else>
struct ARRAY_DEFAULT_IF_TYPE<void, Then, Else> {
typedef Then Result;
};
template <unsigned int array_width, typename DataType, typename DerivedTypeDefault=void>
struct Array {
std::array<DataType, array_width> _data;
typedef typename ARRAY_DEFAULT_IF_TYPE
<
DerivedTypeDefault,
Array,
DerivedTypeDefault
>
::Result DerivedType;
Array() {
for(int index = 0; index < array_width; ++index) _data[index] = 1;
}
DerivedType operator/(const double& data) {
unsigned int column;
DerivedType new_array;
for(column = 0; column < array_width; column++) {
new_array._data[column] = _data[column] / data;
}
return new_array;
}
friend std::ostream& operator<<( std::ostream &output, const Array &array ) {
unsigned int column; output << "(";
for( column=0; column < array_width; column++ ) {
output << array._data[column];
if( column != array_width-1 ) {
output << ", ";
}
}
output << ")"; return output;
}
};
struct Coordinate : public Array<3, double, Coordinate> {
typedef Array< 3, double, Coordinate > SuperClass;
double& x;
double& y;
double& z;
Coordinate() : SuperClass{}, x{this->_data[0]}, y{this->_data[1]}, z{this->_data[2]} {}
};
int main() {
Coordinate coordinate;
std::cout << "coordinate: " << coordinate << std::endl;
Coordinate new_coordinate = coordinate / 10.0;
std::cout << "new_coordinate: " << new_coordinate << std::endl;
Array<5, int> int_array;
std::cout << "int_array: " << int_array << std::endl;
Array<5, int> new_int_array = int_array / 10;
std::cout << "new_int_array: " << new_int_array << std::endl;
}
运行它,您将看到:
coordinate: (1, 1, 1)
new_coordinate: (0.1, 0.1, 0.1)
int_array: (1, 1, 1, 1, 1)
new_int_array: (0, 0, 0, 0, 0)
用doctest进行的单元测试完全实现了我的Array
对象。您需要"doctest.h"
标头来运行它。
#include <array>
#include <cassert>
#include <iostream>
#include <algorithm>
#include <limits>
/**
* 'fabs' : ambiguous call to overloaded function when using templates
* https://stackoverflow.com/questions/10744451/fabs-ambiguous-call-to-overloaded-function-when-using-templates
*/
#include <cmath>
// #define DOCTEST_CONFIG_DISABLE
#ifndef DOCTEST_CONFIG_DISABLE
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#endif
#include "doctest.h"
typedef long double big_double;
constexpr const int MATRICES_DIMENSION = 4;
template<typename condition, typename Then, typename Else>
struct ARRAY_DEFAULT_IF_TYPE {
typedef Else Result;
};
template<typename Then, typename Else>
struct ARRAY_DEFAULT_IF_TYPE<void, Then, Else> {
typedef Then Result;
};
/**
* C++ static polymorphism (CRTP) and using typedefs from derived classes
* https://stackoverflow.com/questions/6006614/c-static-polymorphism-crtp-and-using-typedefs-from-derived-classes
*/
template <unsigned int array_width, typename DataType, typename DerivedTypeDefault=void>
struct Array
{
typedef typename ARRAY_DEFAULT_IF_TYPE<DerivedTypeDefault, Array, DerivedTypeDefault>::Result DerivedType;
/**
* Is it okay to inherit implementation from STL containers, rather than delegate?
* https://stackoverflow.com/questions/2034916/is-it-okay-to-inherit-implementation-from-stl-containers-rather-than-delegate
*/
std::array<DataType, array_width> _data;
/**
* std::array constructor inheritance
* https://stackoverflow.com/questions/24280521/stdarray-constructor-inheritance
*/
Array() {
}
Array(std::initializer_list< DataType > new_values) {
unsigned int data_size = new_values.size();
unsigned int column_index = 0;
// std::cout << data_size << std::endl;
if( data_size == 0 ) {
std::cerr << "Welcome to the Ubuntu 16.04 awesome got nuts bug!\n";
std::cerr << "Just give a look into his nonsense " << std::endl;
std::cerr << "Array(new_values), " << "data_size: " << data_size << ", " << "array_width: " << array_width << std::endl;
}
else if( data_size == 1 ) {
this->clear(*(new_values.begin()));
}
else {
assert(data_size == array_width);
for( auto column : new_values ) {
this->_data[column_index] = column;
column_index++;
}
}
}
/**
* Overloads the `[]` array access operator, allowing you to access this class objects as the
* where usual `C` arrays.
*
* How to implement bound checking for std::array?
* https://stackoverflow.com/questions/49419089/how-to-implement-bound-checking-for-stdarray
*
* @param line the current line you want to access
* @return a pointer to the current line
*/
DataType operator[](unsigned int line) && {
assert(line < array_width);
return this->_data[line];
}
DataType const& operator[](unsigned int line) const& {
assert(line < array_width);
return this->_data[line];
}
DataType& operator[](unsigned int line) & {
assert(line < array_width);
return this->_data[line];
}
/**
* Generic Data to Object operators.
*/
bool operator<=(const DataType& data) const {
for( unsigned int index = 0; index < array_width; index++ ) {
if( this->_data[index] > data ) {
return false;
}
} return true;
}
bool operator<(const DataType& data) const {
for( unsigned int index = 0; index < array_width; index++ ) {
if( this->_data[index] >= data ) {
return false;
}
} return true;
}
bool operator>=(const DataType& data) const {
for( unsigned int index = 0; index < array_width; index++ ) {
if( this->_data[index] < data ) {
return false;
}
} return true;
}
bool operator>(const DataType& data) const {
for( unsigned int index = 0; index < array_width; index++ ) {
if( this->_data[index] <= data ) {
return false;
}
} return true;
}
bool operator==(const DataType& data) const {
for( unsigned int index = 0; index < array_width; index++ ) {
if( this->_data[index] != data ) {
return false;
}
} return true;
}
bool operator!=(const DataType& data) const {
for( unsigned int index = 0; index < array_width; index++ ) {
if( this->_data[index] == data ) {
return false;
}
} return true;
}
DerivedType operator-() const {
DerivedType new_array;
for( unsigned int index = 0; index < array_width; index++ ) {
new_array._data[index] = -_data[index];
}
return new_array;
}
DerivedType operator+(const big_double& data) {
DerivedType new_array;
for( unsigned int index = 0; index < array_width; index++ ) {
new_array._data[index] = _data[index] + data;
}
return new_array;
}
DerivedType operator-(const big_double& data) {
DerivedType new_array;
for( unsigned int index = 0; index < array_width; index++ ) {
new_array._data[index] = _data[index] - data;
}
return new_array;
}
DerivedType& operator+=(const big_double& data) {
for( unsigned int index = 0; index < array_width; index++ ) {
this->_data[index] += data;
}
return *static_cast<DerivedType*>(this);
}
DerivedType& operator-=(const big_double& data) {
for( unsigned int index = 0; index < array_width; index++ ) {
this->_data[index] -= data;
}
return *static_cast<DerivedType*>(this);
}
DerivedType operator/(const double& data) {
unsigned int column;
DerivedType new_array;
for(column = 0; column < array_width; column++) {
new_array._data[column] = _data[column] / data;
}
return new_array;
}
DerivedType divide(const double& data) {
DerivedType result = this->operator/(data);
_data = result._data;
return result;
}
/**
* Object to Object operators.
*/
bool operator<=(const Array& object) const {
for( unsigned int index = 0; index < array_width; index++ ) {
if( this->_data[index] > object._data[index] ) {
return false;
}
} return true;
}
bool operator<(const Array& object) const {
for( unsigned int index = 0; index < array_width; index++ ) {
if( this->_data[index] >= object._data[index] ) {
return false;
}
} return true;
}
bool operator>=(const Array& object) const {
for( unsigned int index = 0; index < array_width; index++ ) {
if( this->_data[index] < object._data[index] ) {
return false;
}
} return true;
}
bool operator>(const Array& object) const {
for( unsigned int index = 0; index < array_width; index++ ) {
if( this->_data[index] <= object._data[index] ) {
return false;
}
} return true;
}
bool operator==(const Array& object) const {
for( unsigned int index = 0; index < array_width; index++ ) {
if( this->_data[index] != object._data[index] ) {
return false;
}
} return true;
}
bool operator!=(const Array& object) const {
for( unsigned int index = 0; index < array_width; index++ ) {
if( this->_data[index] == object._data[index] ) {
return false;
}
} return true;
}
template<typename BaseClass>
DerivedType operator+(const Array< array_width, DataType, BaseClass >& array) {
unsigned int column;
DerivedType new_array;
for(column = 0; column < array_width; column++) {
new_array._data[column] = _data[column] + array._data[column];
}
return new_array;
}
template<typename BaseClass>
DerivedType operator-(const Array< array_width, DataType, BaseClass >& array) {
unsigned int column;
DerivedType new_array;
for(column = 0; column < array_width; column++) {
new_array._data[column] = _data[column] - array._data[column];
}
return new_array;
}
template<typename BaseClass>
DerivedType& operator+=(const Array< array_width, DataType, BaseClass >& array) {
unsigned int column;
for(column = 0; column < array_width; column++) {
_data[column] += array._data[column];
}
return *static_cast<DerivedType*>(this);
}
template<typename BaseClass>
DerivedType& operator-=(const Array< array_width, DataType, BaseClass >& array) {
unsigned int column;
for(column = 0; column < array_width; column++) {
_data[column] -= array._data[column];
}
return *static_cast<DerivedType*>(this);
}
template<typename BaseClass>
DerivedType operator*(const Array< array_width, DataType, BaseClass >& array) {
unsigned int column;
DerivedType new_array;
for(column = 0; column < array_width; column++) {
new_array._data[column] = _data[column] * array._data[column];
}
return new_array;
}
template<typename BaseClass>
DerivedType& multiply(const Array< array_width, DataType, BaseClass >& array) {
_data = this->operator*(array)._data;
return *static_cast<DerivedType*>(this);
}
/**
* The Array<> type includes the Matrix<> type, because you can multiply a `Array` by an `Matrix`,
* but not a vice-versa.
*/
template<typename BaseClass>
DerivedType& multiply(const Array
<
array_width,
Array< array_width, DataType, BaseClass >,
Array< array_width, DataType, BaseClass >
> matrix)
{
unsigned int column;
unsigned int step;
DataType old_array[array_width];
for(column = 0; column < array_width; column++)
{
old_array [column] = this->_data[column];
this->_data[column] = 0;
}
for(column = 0; column < array_width; column++)
{
for(step = 0; step < array_width; step++)
{
this->_data[column] += old_array[step] * matrix._data[step][column];
}
}
return *static_cast<DerivedType*>(this);
}
/**
* Set all the values on the array to the specified single data parameter.
*
* @param `initial` the value to the used
*/
void clear(const DataType initial = 0) {
unsigned int column_index = 0;
for( ; column_index < array_width; column_index++ ) {
this->_data[column_index] = initial;
}
}
/**
* Prints a more beauty version of the array when called on `std::cout << array << std::end;`
*/
friend std::ostream& operator<<( std::ostream &output, const Array &array ) {
unsigned int column;
output << "(";
for( column=0; column < array_width; column++ ) {
output << array._data[column];
if( column != array_width-1 ) {
output << ", ";
}
}
output << ")";
return output;
}
};
/**
* Overloading operators in derived class
* https://stackoverflow.com/questions/5679073/overloading-operators-in-derived-class
*
* C++ static polymorphism (CRTP) and using typedefs from derived classes
* https://stackoverflow.com/questions/6006614/c-static-polymorphism-crtp-and-using-typedefs-from-derived-classes
*/
struct Coordinate : public Array<MATRICES_DIMENSION, big_double, Coordinate>
{
typedef Array< MATRICES_DIMENSION, big_double, Coordinate > SuperClass;
/**
* C++ member variable aliases?
* https://stackoverflow.com/questions/494597/c-member-variable-aliases
*
* Memory allocation for references
* https://stackoverflow.com/questions/11661266/memory-allocation-for-references
*
* Does reference variable occupy memory?
* https://stackoverflow.com/questions/29322688/does-reference-variable-occupy-memory
*/
big_double& x;
big_double& y;
big_double& z;
big_double& w;
Coordinate() :
SuperClass{},
x{this->_data[0]},
y{this->_data[1]},
z{this->_data[2]},
w{this->_data[3]}
{
this->w = 1.0;
}
Coordinate(big_double initial) :
SuperClass{initial},
x{this->_data[0]},
y{this->_data[1]},
z{this->_data[2]},
w{this->_data[3]}
{
this->w = 1.0;
}
Coordinate(big_double x, big_double y, big_double z) :
SuperClass{x, y, z, 1.0},
x{this->_data[0]},
y{this->_data[1]},
z{this->_data[2]},
w{this->_data[3]}
{
}
Coordinate(const Coordinate& object) :
SuperClass{object},
x{this->_data[0]},
y{this->_data[1]},
z{this->_data[2]},
w{this->_data[3]}
{
}
Coordinate& operator=(const Coordinate& object)
{
SuperClass::operator=(object);
this->x = this->_data[0];
this->y = this->_data[1];
this->z = this->_data[2];
this->w = this->_data[3];
return *this;
}
~Coordinate()
{
}
/**
* Data to Object operators.
*
* Comparing doubles
* https://stackoverflow.com/questions/4010240/comparing-doubles
*
* What's a good way to check for ``close enough'' floating-point equality?
* http://c-faq.com/fp/fpequal.html
*/
bool operator==(const big_double& data) const
{
for( unsigned int index = 0; index < MATRICES_DIMENSION; index++ )
{
if( this->_data[index] == data
|| std::fabs(this->_data[index] - data)
< std::fabs( std::min( this->_data[index], data ) ) * std::numeric_limits< big_double >::epsilon() )
{
return false;
}
}
return true;
}
/**
* Object to Object precision comparison.
*/
bool operator==(const Coordinate& object) const
{
for( unsigned int index = 0; index < MATRICES_DIMENSION; index++ )
{
if( this->_data[index] == object._data[index]
|| std::fabs(this->_data[index] - object._data[index])
< std::fabs( std::min( this->_data[index], object._data[index] ) ) * std::numeric_limits< big_double >::epsilon() )
{
return false;
}
}
return true;
}
};
/**
* C++ Matrix Class
* https://stackoverflow.com/questions/2076624/c-matrix-class
*
* A proper way to create a matrix in c++
* https://stackoverflow.com/questions/618511/a-proper-way-to-create-a-matrix-in-c
*
* error: incompatible types in assignment of 'long int (*)[4]' to 'long int [4][4]'
* https://stackoverflow.com/questions/49312484/error-incompatible-types-in-assignment-of-long-int-4-to-long-int
*/
template <unsigned int matrix_width=3, unsigned int matrix_height=3, typename DataType=long int>
struct Matrix : public Array
<
matrix_height,
Array< matrix_width, DataType >,
Array< matrix_width, DataType >
>
{
Matrix()
{
}
Matrix(const DataType initial)
{
this->clear(initial);
}
Matrix(const std::initializer_list< std::initializer_list< DataType > > raw_data)
{
// std::cout << raw_data.size() << std::endl;
assert(raw_data.size() == matrix_height);
// std::cout << raw_data.begin()->size() << std::endl;
assert(raw_data.begin()->size() == matrix_width);
unsigned int line_index = 0;
unsigned int column_index;
for( auto line : raw_data )
{
column_index = 0;
for( auto column : line )
{
this->_data[line_index][column_index] = column;
column_index++;
}
line_index++;
}
}
void clear(const DataType initial=0)
{
unsigned int line;
unsigned int column;
for( line=0; line < matrix_height; line++ )
{
for( column=0; column < matrix_width; column++ )
{
this->_data[line][column] = initial;
}
}
}
void multiply(const Matrix matrix)
{
unsigned int line;
unsigned int column;
unsigned int step;
DataType old_matrix[matrix_height][matrix_width];
for(line = 0; line < matrix_height; line++)
{
for(column = 0; column < matrix_width; column++)
{
old_matrix[line][column] = this->_data[line][column];
this->_data[line][column] = 0;
}
}
for(line = 0; line < matrix_height; line++)
{
for(column = 0; column < matrix_width; column++)
{
for(step = 0; step < matrix_width; step++)
{
this->_data[line][column] += old_matrix[line][step] * matrix._data[step][column];
}
// std::cout << "this->_data[line][column] = " << this->_data[line][column] << std::endl;
}
}
// If you would like to preserve the original value, it can be returned here
// return old_matrix;
}
/**
* Prints a more beauty version of the matrix when called on `std::cout<< matrix << std::end;`
*/
friend std::ostream& operator<<( std::ostream &output, const Matrix &matrix )
{
unsigned int line;
unsigned int column;
output << "{";
for( line=0; line < matrix_height; line++ )
{
output << "(";
for( column=0; column < matrix_width; column++ )
{
output << matrix._data[line][column];
if( column != matrix_width-1 )
{
output << ", ";
}
}
if( line != matrix_height-1 )
{
output << "), ";
}
else
{
output << ")";
}
}
output << "}";
return output;
}
};
struct MatrixForm : public Matrix<MATRICES_DIMENSION, MATRICES_DIMENSION, big_double>
{
// Inheriting constructors
// https://stackoverflow.com/questions/347358/inheriting-constructors
using Matrix< MATRICES_DIMENSION, MATRICES_DIMENSION, big_double >::Matrix;
};
TEST_CASE("Testing basic coordinate initialization with a constant value")
{
Coordinate coordinate{2};
std::ostringstream contents;
contents << coordinate;
CHECK( "(2, 2, 2, 1)" == contents.str() );
}
TEST_CASE("Testing basic coordinate sum by scalar") {
std::ostringstream contents;
Coordinate coordinate{1.0};
Coordinate new_coordinate = coordinate + 10.0;
std::ostringstream().swap(contents); contents << new_coordinate;
CHECK( "(11, 11, 11, 11)" == contents.str() );
std::ostringstream().swap(contents); contents << coordinate;
CHECK( "(1, 1, 1, 1)" == contents.str() );
}
TEST_CASE("Testing basic coordinate sum and attribution by scalar") {
std::ostringstream contents;
Coordinate coordinate{1.0};
coordinate += 10.0;
std::ostringstream().swap(contents); contents << coordinate;
CHECK( "(11, 11, 11, 11)" == contents.str() );
}
TEST_CASE("Testing basic coordinate sum by another coordinate") {
std::ostringstream contents;
Coordinate coordinate{1.0};
Coordinate another_coordinate{2.0};
Coordinate new_coordinate = coordinate + another_coordinate;
std::ostringstream().swap(contents); contents << new_coordinate;
CHECK( "(3, 3, 3, 2)" == contents.str() );
std::ostringstream().swap(contents); contents << coordinate;
CHECK( "(1, 1, 1, 1)" == contents.str() );
}
TEST_CASE("Testing basic coordinate sum and attribution by another coordinate") {
std::ostringstream contents;
Coordinate coordinate{1.0};
Coordinate another_coordinate{2.0};
coordinate += another_coordinate;
std::ostringstream().swap(contents); contents << coordinate;
CHECK( "(3, 3, 3, 2)" == contents.str() );
}
TEST_CASE("Testing basic coordinate negative operator") {
std::ostringstream contents;
Coordinate coordinate{1.0};
Coordinate new_coordinate = -coordinate;
std::ostringstream().swap(contents); contents << new_coordinate;
CHECK( "(-1, -1, -1, -1)" == contents.str() );
std::ostringstream().swap(contents); contents << coordinate;
CHECK( "(1, 1, 1, 1)" == contents.str() );
}
TEST_CASE("Testing basic coordinate difference by scalar") {
std::ostringstream contents;
Coordinate coordinate{1.0};
Coordinate new_coordinate = coordinate - 10.0;
std::ostringstream().swap(contents); contents << new_coordinate;
CHECK( "(-9, -9, -9, -9)" == contents.str() );
std::ostringstream().swap(contents); contents << coordinate;
CHECK( "(1, 1, 1, 1)" == contents.str() );
}
TEST_CASE("Testing basic coordinate difference and attribution by scalar") {
std::ostringstream contents;
Coordinate coordinate{1.0};
coordinate -= 10.0;
std::ostringstream().swap(contents); contents << coordinate;
CHECK( "(-9, -9, -9, -9)" == contents.str() );
}
TEST_CASE("Testing basic coordinate difference by another coordinate") {
std::ostringstream contents;
Coordinate coordinate{1.0};
Coordinate another_coordinate{2.0};
Coordinate new_coordinate = coordinate - another_coordinate;
std::ostringstream().swap(contents); contents << new_coordinate;
CHECK( "(-1, -1, -1, 0)" == contents.str() );
std::ostringstream().swap(contents); contents << coordinate;
CHECK( "(1, 1, 1, 1)" == contents.str() );
}
TEST_CASE("Testing basic coordinate difference and attribution by another coordinate") {
std::ostringstream contents;
Coordinate coordinate{1.0};
Coordinate another_coordinate{2.0};
coordinate -= another_coordinate;
std::ostringstream().swap(contents); contents << another_coordinate;
CHECK( "(2, 2, 2, 1)" == contents.str() );
std::ostringstream().swap(contents); contents << coordinate;
CHECK( "(-1, -1, -1, 0)" == contents.str() );
}
TEST_CASE("Testing basic coordinate multiplication") {
std::ostringstream contents;
Coordinate coordinate1{1};
Coordinate coordinate2{2};
coordinate1.multiply(coordinate1);
std::ostringstream().swap(contents); contents << coordinate1;
CHECK( "(1, 1, 1, 1)" == contents.str() );
coordinate1.multiply(coordinate2);
std::ostringstream().swap(contents); contents << coordinate2;
CHECK( "(2, 2, 2, 1)" == contents.str() );
}
TEST_CASE("Testing basic coordinate division by scalar") {
std::ostringstream contents;
Coordinate coordinate{1.0};
Coordinate new_coordinate = coordinate / 10.0;
std::ostringstream().swap(contents); contents << new_coordinate;
CHECK( "(0.1, 0.1, 0.1, 0.1)" == contents.str() );
std::ostringstream().swap(contents); contents << coordinate;
CHECK( "(1, 1, 1, 1)" == contents.str() );
new_coordinate = coordinate.divide(100.0);
std::ostringstream().swap(contents); contents << new_coordinate;
CHECK( "(0.01, 0.01, 0.01, 0.01)" == contents.str() );
std::ostringstream().swap(contents); contents << coordinate;
CHECK( "(0.01, 0.01, 0.01, 0.01)" == contents.str() );
}
TEST_CASE("Testing basic array division by scalar") {
std::ostringstream contents;
Array<5, double> array{1};
std::ostringstream().swap(contents); contents << array;
CHECK( "(1, 1, 1, 1, 1)" == contents.str() );
Array<5, double> new_array = array / 10.0;
std::ostringstream().swap(contents); contents << new_array;
CHECK( "(0.1, 0.1, 0.1, 0.1, 0.1)" == contents.str() );
}
TEST_CASE("Testing basic matrix multiplication") {
std::ostringstream contents;
Coordinate coordinate{2};
MatrixForm matrix{
{1, 0, 0, 0},
{0, 1, 0, 0},
{0, 0, 1, 0},
{0, 0, 0, 1}
};
matrix.multiply(matrix);
coordinate.multiply(matrix);
// https://stackoverflow.com/questions/2848087/how-to-clear-stringstream
std::ostringstream().swap(contents); contents << coordinate;
CHECK( "(2, 2, 2, 1)" == contents.str() );
std::ostringstream().swap(contents); contents << matrix;
CHECK( "{(1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1)}" == contents.str() );
}
您可以使用以下方法进行构建:
g++ -o test application.cpp --std=c++11
运行它,您将看到:
[doctest] doctest version is "2.0.1"
[doctest] run with "--help" for options
===============================================================================
[doctest] test cases: 14 | 14 passed | 0 failed | 0 skipped
[doctest] assertions: 26 | 26 passed | 0 failed |
[doctest] Status: SUCCESS!
[Finished in 5.2s]