I have a group of functions which perform similar action on different input parameter classes ParamX, ParamY, ParamZ. They have a general form like:
Result funcX(ParamX param){
auto result = param.getX(); // param.getY() in case of ParamY
// check result is valid
if(!result.valid()){
// print a log message for ParamX
return {};
}
return result.value();
}
Result is a templated struct like Result<ParamX>, based on the type of input parameter class ParamX.
Also note that each param will call a completely different function param.getX(), param.getY(), param.getZ()
So given I have several different functions funcX, funcY, funcZ, each acting on ParamX, ParamY, ParamZ separately, how do I convert this into a single template function?
Also note that in the future, any developer can make another ParamA, ParamB .... class with different getA(), getB() methods, so nothing is fixed.
given I have several different functions funcX, funcY, funcZ, each acting on ParamX, ParamY, ParamZ separately, how do I convert this into a single template function?
You can make use of function templates and auto type deduction(using the auto type specifier in the return type) as shown below:
template<typename ParamX>
//--vvvv---------------------->auto type deduction
auto funcX(ParamX param){
auto result = param.getX();
// check result is valid
if(!result.valid()){
// print a log message for ParamX
// add appropriate return statement if needed
}
return result.value();
}
Edit
Now since you've edited your question to specify that each of the passed arguments will have their own getter, you can use the following code.
Solution 1
Here we make use of pointer to member function as the second argument to the function template.
#include <iostream>
#include<string>
struct Name
{
bool valid()
{
return true;
}
int value ()
{
return 5;
}
};
struct Server1
{
Name getX()
{
std::cout<<"getX called"<<std::endl;
return Name();
}
};
struct Server2
{
Name getY()
{
std::cout<<"getY called"<<std::endl;
return Name();
}
};
template<typename ParamX, typename RType>
//--vvvv---------------------->auto type deduction
auto funcX(ParamX param,RType (ParamX::*callable)()){
std::cout<<"funcX called"<<std::endl;
auto result = ((param.*callable)());
// check result is valid
if(!result.valid()){
// print a log message for ParamX
// add appropriate return statement if needed
}
return result.value();
}
int main()
{
funcX(Server1(), &Server1::getX);
funcX(Server2(), &Server2::getY);
return 0;
}
Demo
The output of the above is:
funcX called
getX called
funcX called
getY called
Solution 2
This is a variation of solution 1 above. Here the second argument of the function template is taken as a reference to const.
#include <iostream>
#include<map>
#include<string>
#include<vector>
struct Name
{
bool valid()
{
return true;
}
int value ()
{
return 5;
}
};
struct Server1
{
Name getX()
{
std::cout<<"getX called"<<std::endl;
return Name();
}
};
struct Server2
{
Name getY()
{
std::cout<<"getY called"<<std::endl;
return Name();
}
};
template<typename ParamX, typename Callable>
//--vvvv---------------------->auto type deduction
auto funcX(ParamX param, const Callable& callable){
std::cout<<"funcX called"<<std::endl;
auto result = (param.*callable)();
// check result is valid
if(!result.valid()){
// print a log message for ParamX
// add appropriate return statement if needed
}
return result.value();
}
int main()
{
funcX(Server1(), &Server1::getX);
funcX(Server2(), &Server2::getY);
return 0;
}
Demo
Assuming this was requirements above:
template <typename TParam,typename TResult>
TResult funcX(TParam param){
auto result = param.getX();
// check result is valid
if(!result.valid()){
// print a log message for ParamX
return {};
}
return result.value();
}
Note if you want to generalize coordinate you can invoke template compile time polymorpism by implying a member(in this case its getx of tparam). If you want to generalize u just need to agree on a name.
Alternatively if performance not important u can do runtime polymorpism via a virtual member. This doesnt require a template.
If u want a complicated template example have a look at my non blocking network templates here:
https://bitbucket.org/ptroen/crossplatformnetwork/src/master/OSI/Application/Stub/HTTPSServer/httpsserver.cc
It depends on the properties of ParamX, Result<ParamX>, and the other types to some extent.
But, assuming (since you haven't specified)
You have a templated type Result such that Result<ParamX> is the result corresponding to a ParamX, and Result<ParamY> is the result corresponding to a ParamY
Result<ParamX> is default constructible (so it will be constructed in return {} for a function that returns Result<ParamX>;
ParamX, ParamY, etc all have a member function getX();
The return type of that getX() function is implicitly convertible to Result<ParamX>;
The return type of that getX() function has a member function named valid() that returns an integral type (where a zero or false return indicates invalid);
You might do something like
template<class Param> Result<Param> func(Param param)
{
auto result = param.getX();
// check result is valid
if(!result.valid())
{
// print a log message
return {};
}
return result.value();
}
Then, to use that function you might do;
ParamX px;
Result<ParamX> result = Result(px); // Result(px) is equivalent to Result<ParamX>(px)
auto result2 = Result(px); // compiler will deduce the type of result2 as Result<ParamX>
ParamY py;
Result<ParamY> result = Result(py); // Result(py) is equivalent to Result<ParamY>(py)
Note I'm making a lot of assumptions in the above, to fill in information you have not provided. You need to make a similar set in your code and (more importantly) ensure they are true.
Related
I would like to place a std::variant inside a class and return its elements with a template function. Here is an example:
#include <string>
#include <variant>
class Class {
public:
std::variant<std::string, double> cont;
Class() {}
template <class V> Class(const V v) { cont = v; }
template <typename V> V fun() {
if (std::holds_alternative<double>(cont))
return std::get<double>(cont);
else if (std::holds_alternative<std::string>(cont))
return std::get<std::string>(cont);
}
};
int main() {
Class c;
c = 20;
double d = c.fun<double>();
return 0;
}
I try to return the elements of the class Class through the template function fun. However, gcc-9.1 refuses to compile the code and tells me
Class.cpp:12:46: error: cannot convert ‘std::__cxx11::basic_string<char>’ to ‘double’ in return
12 | return std::get<std::string>(cont);
Why is there any attempt to convert the string (the second return type of the function foo) to a double? Can I prevent this and solve the problem? Do I use the std::variant class unidiomatic?
The issue here is that you query the current value stored at runtime, while the function signature of the template instantiation is performed at compile time. Consider how the member function looks like when you try using it to retrieve a double:
double fun() {
if (/* ... */)
return std::get<double>(cont); // Ok return type is double, too
else if (/* ... */)
return std::get<std::string>(cont); // Error, return type should be string?!
}
This can't work. You need to change the way to access the data member, e.g. passing an overload set to std::visit, by providing two getter-like functions returning std::optional<double> and std::optional<std::string> or something similar.
All runtime if branches must be compilable even if not taken. If we call fun() with V == double then returning an std::string makes no sense and causes the error (even if that branch would never be taken, the compiler can't know that for certain).
Instead, just return it right away through V:
template <typename V> V fun() {
if (std::holds_alternative<V>(cont))
return std::get<V>(cont);
return {}; // return default constructed V. You could throw an exception here instead etc.
}
I'm wrapping a C function in a C++ function. The C function accepts a function pointer (with state). I want to allow a C++ callable. A code sample says a thousand words so...
//======================================================
// All this stuff is defined in C somewhere else
// C string type
typedef struct FooString { const char* str; size_t length; } FooString;
// C function pointer type
// This keeps getting called until it returns something with length == 0
typedef FooString (*CFunctionPointer)(void* state);
// Function being wrapped
void quux(CFunctionPointer fPtr, void* state)
{
FooString str;
while(1)
{
str = fPtr(state);
if(str.length == 0)
break;
else
{
// do something
}
}
}
//======================================================
// Here's what I need help with
template<typename IteratorFunctor>
void quuxWrapper(IteratorFunctor& iterator) const
{
// type that the functor returns, and related types
using TIn = decltype(iterator());
using TNoRef = typename std::remove_reference<TIn>::type;
using TYesRef = typename std::add_lvalue_reference<TNoRef>::type;
using TStored = typename std::conditional<std::is_reference<TIn>::value, std::reference_wrapper<TNoRef>, TIn>::type;
// store this on the stack in this function, and pass a pointer to it into the C library
// the C callback will pass back the pointer, and we can get at all this stuff from within the lambda
struct CallbackContext
{
bool isFirst; // is this the first iteration?
IteratorFunctor& iterator; // reference to the iterator in a place we can get to from inside the C function pointer callback
TStored current; // current value (either an actual value stored on the stack, or a reference wrapper)
};
CFunctionPointer cFunctionPtr = [](void* pContext) -> FooString
{
CallbackContext& context = *((CallbackContext*) pContext);
// on the first iteration, we return the value already fetched (need to do this to support things that
// aren't DefaultConstructable). On subsequent iterations, call the functor again.
if(context.isFirst)
context.isFirst = false;
else
context.current = context.iterator();
// this is needed for supporting both references as reference_wrappers and value types. we take a reference
// which forces reference_wrapper to call its conversion operator and is basically a no-op for value types
// (something like context.current.length would fail for reference_wrapper)
TYesRef current = context.current;
// stop iteration if functor returns anything with length 0
if(current.length() == 0)
return FooString{nullptr, 0};
else
return FooString{current.data(), current.length()};
};
// create the context and make the first call to the iterator
CallbackContext context{true, iterator, iterator()};
// and then call the C function
quux(cFunctionPtr, &context);
}
This supports returning a std::string or std::string& from the functor. It also allows users to return their own type, as long as that type has length() and data() methods. It doesn't allow the functor to return a std::string*, though, which is what I'd like to support.
Is there a good way to do this using C++11 features (and no dependencies or weird compiler hacks, since this is part of the public API)?
template<class F, class R=std::result_of_t<F&()>>
struct c_callback {
F state;
void* get_pvoid() { return std::addressof(state); }
using C_sig = R(*)(void*);
static C_sig get_pfunc() {
return [](void* pvoid)->R {
F* pstate = static_cast<F*>(pvoid);
return static_cast<R>( (*state)() );
};
}
};
this wraps a lambda or other C++ invokable into a function pointer and pvoid. It does nothing else. The return value is either deduced or passed.
Your second problem is wanting to adapt return values.
template<class T>
FooString to_foostring_f( T& t ) {
return {t.data(), t.length()};
}
template<class T>
FooString to_foostring_f( T* t ) {
if (!t) return {0,0};
return to_foostring_f(*t);
}
auto to_foostring = [](auto&& t)->FooString {
return to_foostring_f( decltype(t)(t) );
};
to_foostring is a function object that takes something, and returns a FooString. It does this by calling to_foostring_f. You can enhance it with ADL.
Finally write compose(First, Second) which returns Second(First(Args...)).
Stitch these together and it should work.
I have a class which takes an input, and sometimes I'd like to set that input by assigning a variable, and at other times I'd like the class to call a function to get its input.
In the past, I'd have just used a std::function<T()> as the input, and set a lambda to return the value of some external variable, but I'm trying to wean off an overuse of std::function. So I came up with std::variant<T, std::function<T()>>:
template <typename T>
using functionable = std::variant<T, std::function<T()>>;
// return the T or the result of the T() from the variant
template <typename T>
T get(const functionable<T>& f) {
if (f.index() == 0)
return std::get<0>(f);
else
return std::get<1>(f)();
}
Implemented thus:
class SomeClass {
private:
functionable<int> input_{0};
public:
SomeClass(const functionable<int>& input) : input_{input} {}
SomeClass& operator=(const functionable<int>& rhs) {
input_ = rhs;
return *this;
}
void print() { std::cout << get(input_) << '\n'; }
And used flexibly thus:
SomeClass foo {42}; // init with assigned value
foo.print();
foo = 101; // overwrite assigned value
foo.print();
bool a{true};
// replace input value with input lambda
foo { [this]{if(a) return 10; else return 20;} };
foo.print();
a = !a; // useful if input predicates change
foo.print();
foo = 101; // replace std::function input with assigned int
foo.print();
Is this an improvement over solely using a std::function<T()> for the input and using foo = []{return 42;} for fixed input values?
An alternative would be to make separate subclasses for assigned vs called inputs but that resulted in combinatorial explosion when there's more than one input. Are there other alternatives I'm missing?
Mathematically speaking, the constant function is just another function. And in this C++ example, there seems to be no motivating reason to treat the constant function as a special case. Performance is likely to be approximately the same, unless the large majority of your inputs are constants.
Additionally, this functionable cannot be used with std::generate, while a std::function<> wrapping a constant can. That's fixable of course by wrapping functionable in a class of its own or capturing one in another lambda. But it's just adding complexity when the simple solution will do.
I have a function that should return an object of class A if i is positive, return an integer else.
This is a strong simplified example, and i can not use overloading !
#include <iostream>
template <typename T>
T& function(int i){
T res;
if (i>0){
A res = 1;
}
else{
int res = 5;
}
return res;
}
int main(){
A res1 = function(5);
int res2 = function(-5;)
return 0;
}
Types are static, determined when the code is compiled, so you can't have a different return type depending on a run-time value. A function can only return one type.
One option is to use a discriminated union; a union of the different types you want to support, along with an enumerated value to indicate which type is active. This is quite tricky to implement if you want to support general class types, so you might want to look at Boost's Variant library. For example:
boost::variant<int,T> function(int i) {
if (i>0)
return A{1};
else
return int{5};
}
int main() {
A res1 = boost::get<A>(function(5));
int res2 = boost::get<int>(funtion(-5);
}
Another option might be to provide a set of callback functions for different types, and handle the value there rather than returning it. For example:
template <typename Callback>
void function(int i, Callback & callback)
if (i>0)
callback(A{1});
else
callback(int{5});
}
struct MyCallback {
void operator()(A const &) {/* do something with A */}
void operator()(int) {/* do something with int */}
};
int main() {
MyCallback callback;
function(5, callback); // calls callback for A
function(-5, callback); // calls callback for int
}
What you are trying to do is impossible. Your function can only have one return type. You could pass in an A variable and an integer variable by reference and have one or the other set by the function but that's the closest you're going to be able to get. I'm rather unsure of what you are trying to accomplish though.
C++ simply does not support this.
A better solution would be:
bool function(int i, int &intResult, A &AResult)
{
if (i > 0)
{
AResult = A(1);
// Or whatever other code you need to place the result in AResult
return true;
}
intResult = 5;
return false;
}
You need to pass both an int and an A to receive the possible return values, and by inspecting the bool that's returned you know which one was filled in.
The pseudo code for what I want to do is:
function<bool(int)> getFunc(type) // get a function depending on what type is passed
problem is the function to return must be declared as static? As a result, I can't access object properties. So I need to pass them into the function? Thus, the original function to return might look like:
bool func1(int)
bool func2(int)
Now needs to be injected with other objects/arguments it need to run ...
bool func1(int, Class1)
bool func2(int, Class2)
So how do I define the return type of getFunc? Or maybe theres a better way?
UPDATE
In the above, func* functions are actually: has*(). eg.
hasStmtsUsing(variable)
hasVariablesUsed(stmt)
And to determine if the condition is true, it uses an object eg. uses. Then there are other similar has*() functions like hasStmtsModifying(variable) that uses an object modifies. uses and modifies are objects of different types, and originally, they are object members, thus dont need to be passed in. Now since the functions are static, they need to be passed in.
While writing this, I am thinking what I need is some kind of dependency injector? Maybe I pass in DI and call DI.getX() functions?
Maybe I'm misunderstanding something, but isn't all you need to use a memberfunction where you bind() the first parameter?
class X {
bool f1(int);
bool f2(int);
};
X x;
function<bool(int)> f = bind(&X::f1, &x);
Here's an example of how it can be done with lambdas in C++11:
#include <cassert>
#include <functional>
#include <iostream>
struct Class1 {
};
struct Class2 {
};
bool func1(int,Class1)
{
return true;
}
bool func2(int,Class2)
{
return false;
}
inline std::function<bool(int)> getFunc(Class1 obj1)
{
return [=](int x){ return func1(x,obj1); };
}
inline std::function<bool(int)> getFunc(Class2 obj2)
{
return [=](int x){ return func2(x,obj2); };
}
int main(int,char**)
{
Class1 obj1;
std::function<bool(int)> f1 = getFunc(obj1);
Class2 obj2;
std::function<bool(int)> f2 = getFunc(obj2);
assert(f1(0)==true);
assert(f2(0)==false);
return 0;
}