CodeProject
Emulating in, out and inout function parameters in C++.
This is the continuation of Part 1 of this post.
In Part 1, we created classes to represent Input, Output and Input-Output parameters and arguments.
Here is an example how those classes can be used:
#include "param_inout.hpp"
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace param_inout;
using namespace std;
#define PRINT(arg) cout << __FUNCTION__ << ":"
<< __LINE__ << ": "<< arg << " " << endl
double func1(inp<int> p) {
return p * 2.2;
}
void func2(outp<int> p) {
p = 88;
}
void func3(inoutp<string> p) {
auto t = string(p); p = "Hello "; p = string(p) + t; }
void func4(inp<string> pattern,
inp<vector<string>> items,
inoutp<string> message,
outp<int> matchCount) {
PRINT(message.arg());
auto& ritems = items.arg();
matchCount = count_if(begin(ritems), end(ritems),
[&](const string& a) { return a.find(pattern) != string::npos; });
message = "Done";
}
void func5(inp<int> p1, outp<int> p2, inoutp<string> p3) {
func1(ina(p1));
func2(outa(p2));
func3(inouta(p3));
}
int main() {
auto a0 = func1(ina(static_cast<int>(2.2))); PRINT(a0);
auto a1 = func1(ina(2)); PRINT(a1);
auto a2 = 0; func2(outa(a2)); PRINT(a2);
auto a3 = string{"world!"}; func3(inouta(a3)); PRINT(a3);
auto a4 = vector<string>{"avocado",
"apple", "plum", "apricot", "orange"};
auto a5 = string{"Searching..."};
auto a6 = 0;
func4(ina(string{ "ap" }), ina(a4), inouta(a5), outa(a6));
PRINT(a5); PRINT(a6);
func5(ina(5), outa(a6), inouta(a5)); PRINT(a5); PRINT(a6);
return 0;
}
This example code produces the following output:
main:47: 4.4
main:48: 4.4
main:49: 88
main:50: Hello world!
func4:30: Searching...
main:56: Done
main:56: 2
main:58: Hello Done
main:58: 88
In the code example above, it is clear at the parameter declaration how each parameter is used by the function. Also, for declaration, we chose the convention to include a trailing “p
” after the category. For example, outp
signifies an Output Function Parameter. It says that it’s for output and it also says that it’s a parameter (i.e. not an argument).
At the call sites, we pass function arguments using ina
(input), outa
(output) and inouta
(input and output). This way, we can clearly see that they are Function Arguments (not parameters); and how the function is going to use those arguments. No surprises.
It is also obvious how to construct function declarations ourselves. For example, the simple functions at the beginning of this post may be declared like this, regardless who does it:
void f(inoutp<string> s);
void g(inp<string> s);
void caller() {
auto a1 = string{"hello"};
f(inouta(a1));
g(ina(a1));
}
And our std::vector
example will become this:
void f(inp<vector<string>> v);
It is clear what is happening both at the declaration and at the call site. Also, this convention is much easier and obvious to follow.
References
References about the complexity of function parameter declaration guidelines
END OF POST