Questions raised
If I had three matrices, three rows and three columns, one row and nine columns and nine rows and one column, I would like to output them.
- 3 rows and 3 columns
0 0 0 0 0 0 0 0 0
- 1 row 9 columns
0 0 0 0 0 0 0 0 0
- 9 rows and 1 column
0 0 0 0 0 0 0 0 0
Direct thinking
The most direct design should be as follows:
// Which matrix does m_model represent?
// Square represents three rows and three columns
// Horizontal represents one row and nine columns
// Vertical represents nine rows and one column
// m_numbers denotes internal arrays
void Matrix::showMatrix() const {
switch(this->m_model) {
case MatrixModel::Square: {
for(auto index = 0; index != 9; ++index) {
std::cout << this->m_numbers[index] << ((index+1)%3==0 ? '\n':' ');
}
std::cout << std::endl;
break;
}
case MatrixModel::Horizontal: {
for(auto index = 0; index != 9; ++index) {
std::cout << this->m_numbers[index] << ' ';
}
std::cout << std::endl;
break;
}
case MatrixModel::Vertical: {
for(auto index = 0; index != 9; ++index) {
std::cout << this->m_numbers[index] << '\n';
}
std::cout << std::endl;
break;
}
default: {
break;
}
}
}
Generic thinking
Looking at the above code, we find that there are repetitions in semantics:
// ergodic
for(auto index = 0; index != 9; ++index) {
// output
...
// Conditional output
// End line change
}
From the code intuitive point of view, only part of the difference:
// << ((index+1)%3==0 ? '\n':' ');
// << ' ';
// << '\n';
So we pack these three parts separately, what! You don't know what packing to use? Closure in place!
// For the first:
[] () {
static int index = 1;
return ((index++)%3==0 ? '\n':' ');
}
// For the second:
[] () {
return ' ';
}
// For the third:
[] () {
return '\n';
}
The remaining three parts are the same, or in-place closures:
auto output = [this]() {
for(auto i : this->m_numbers) {
std::cout << i;
}
std::cout << std::endl;
};
Then how to use these two things together, with the help of std::function:
auto output = [this](std::function<char(void)> func) {
for(auto i : this->m_numbers) {
std::cout << i << func();
}
std::cout << std::endl;
};
Finally, put them together:
void Matrix::showMatrix() const {
auto output = [this](std::function<char(void)> func) {
for(auto i : this->m_numbers) {
std::cout << i << func();
}
std::cout << std::endl;
};
switch(this->m_model) {
case MatrixModel::Square: {
output([](){
static int index = 1;
return ((index++)%3==0 ? '\n':' ');
});
break;
}
case MatrixModel::Horizontal: {
output([](){
return ' ';
});
break;
}
case MatrixModel::Vertical: {
output([](){
return '\n';
});
break;
}
default: {
break;
}
}
}
Death thinking
Then we noticed that the effect of switch case has nothing to do with output closure. Its result only affects three subclosures. So can we consider compiling output closure only once?
Then bind the switch case and its related parts together:
int index = 1;
auto select = [this,&index](){
switch(this->m_model) {
case MatrixModel::Square: {
return ((index++)%3==0 ? '\n':' ');
}
case MatrixModel::Horizontal: {
return ' ';
}
case MatrixModel::Vertical: {
return '\n';
}
default: {
break;
}
}
};
output(select);
In this way, it seems obscure to write:), in fact, it is two closures:
void Matrix::showMatrix() const {
auto output = [this](std::function<char(void)> func) {
for(auto i : this->m_numbers) {
std::cout << i << func();
}
std::cout << std::endl;
};
int index = 1;
auto select = [this,&index](){
switch(this->m_model) {
case MatrixModel::Square: {
return ((index++)%3==0 ? '\n':' ');
}
case MatrixModel::Horizontal: {
return ' ';
}
case MatrixModel::Vertical: {
return '\n';
}
default: {
break;
}
}
};
output(select);
}
Instantaneous explosion
Remember template parameter derivation and template specialization, I tried to move the switch process to compile time, that is to say, at run time there is no need to consider switch again.
// First define the master template
template <MatrixModel model>
void Matrix::show() const {
std::cout << "None" << std::endl;
}
// Specialization into Square
template <>
void Matrix::show<MatrixModel::Square>() const {
std::cout << "Square" << std::endl;
int index = 0;
for(auto i : this->m_numbers) {
std::cout << i << ((index++)%3==0 ? '\n':' ');
}
std::cout << std::endl;
}
// Special case for Horizontal
template <>
void Matrix::show<MatrixModel::Horizontal>() const {
std::cout << "Horizontal" << std::endl;
for(auto i : this->m_numbers) {
std::cout << i << ' ';
}
std::cout << std::endl;
}
// The case of specialization into Vertical
template <>
void Matrix::show<MatrixModel::Vertical>() const {
std::cout << "Vertical" << std::endl;
for(auto i : this->m_numbers) {
std::cout << i << '\n';
}
std::cout << std::endl;
}
However, the problem arises, resulting in a compilation-time decision on what form to display:
matrix.show<MatrixModel::Square>();
matrix.show<MatrixModel::Horizontal>();
matrix.show<MatrixModel::Vertical>();
In this regard, I can only say: WTF! Only this and nothing more!
CSDN Spicy Chicken MD Editor, No Sequence Tables Lost