Is there have a way to delay type binding at code level in C++? - c++

I'm going to request some user configuration via json from the server that contains two types of data like (usrID, bool), and (usrID, int). so, I created two map to classify and reload two functions with the same name to put the data into the corresponding map after parsed.
For the sake of refinement, I used the auto keyword of C++11 to initialize a variable without assign and determined its type whether bool or int mentioned above through assigned by parse function, so as to call the overloaded function directly to store them.
But it causes compiler error that cannot use a auto variable without assign.
bool fromStringtoBool() {……}
int fromStringtoInt() {……}
void setAppidConfig(int,bool);
void setAppidConfig(int,int);
……
……
void main func()
{
……
int usrId;
auto value;
if(isBool())
{
value = fromStringtoBool();
}
else
{
value = fromStringtoInt();
}
setAppidConfig(usrId,value)
……
}
Is it possible to implement the above logic in C++ ?

No. In C++ auto variable type resolution and also function overload resolution has to happen compile time. The isBool() of yours is presumably runtime value. So all you can do is something like:
if(isBool())
{
setAppidConfig(usrId,fromStringtoBool());
}
else
{
setAppidConfig(usrId,fromStringtoInt());
}

auto allows you to omit the type name and let the compiler deduce the type. There is no type to deduce from in your case, since there's no assignment, so nothing can be deduced.
For your use case, you need some kind of variant type that can store one of several types. The Qt library has QVariant, and other libraries usually offer something like that as well. As of C++17 however, such a type is offered directly by the standard library: std::variant.
int usrId;
std::variant<bool, int> value;
if (isBool()) {
value = fromStringtoBool();
} else {
value = fromStringtoInt();
}
setAppidConfig(usrId, value);
The setAppidConfig() function would need to accept an appropriate variant parameter:
void setAppidConfig(int usrId, std::variant<bool, int> value)
{
// ...
if (std::holds_alternative<int>(value)) {
// It's a int.
int i = std::get<int>(value);
} else {
// It's a bool.
bool b = std::get<bool>(value);
}
}
Note that variants can hold more than just two types (you can have an std::variant<bool, int, std::string> for example.)
If you need something that can hold anything, then you can use an std::any. This type does not need to know the types in advance (it takes no template arguments.)

Related

pybind11 variable return type

I have a C++ class which acts like a map that can contain different data types.
In C++, it is unknown at compile time what data type an entry is. Therefore, the programmer has to know and the accessor is templated:
auto a = map.get<int>("my-int-entry");
auto b = map.get<std::string>("my-string-entry");
At runtime, the map knows what type the entries have. So in python, I should be able to use the runtime type information.
a = map.get('my-int-entry') # a is of type int
b = map.get('my-string-entry') # b is of type string
I'd like that it looks up the type information at runtime, then calls get<int> if the runtime type is int, otherwise get<std::string>. Is there a way to do this directly in pybind11?
Or do I need another (pure python) function that calls the respectively mapped C++ functions?
I'm not sure how you would query your map in runtime about what type a key has, but this is the general idea of how I would do that:
map_wrapper.def("get", [](Map& self, const std::string& key) -> py::object {
if (self.is_a<int>(key)) {
return py::cast(self.get<int>(key));
} else if (self.is_a<std::string>(key)) {
return py::cast(self.get<std::string>(key));
} else if ...
});
You would need to know the types you want to support in advance.

Calling a Function with integer [[mayb_unused]] macro and default argument boolean type parameter

I am writing a Function with 2 Parameters, 1st is integer type marked [[maybe_unused]] and 2nd is Boolean Type with Default Argument false.
int preOrderTraversial([[maybe_unused]] int searchData, bool forDisplay = false)
This is the function declaration. The function is used for pre-order Traversal in Binary Search Tree. I want to use the same function for Displaying the Tree and Traversing it for searching a Node with specific Data. But only for 1 of both problems at once. Not for searching AND displaying you see.
So, obviously, it works fine for the searching part but when I call the function for Displaying the function call looks like this:
preOrderTraversal(true)
or
bool forDisplay = true;
preOrderTraversal(forDisplay);
Now the Compiler (even with the parameter DECLARED as a BOOL) still considers this bool parameter as an int and uses it for searchData (integer) parameter of the function and not for the forDisplay (bool) parameter.
Is there a way to force or tell compiler which of both parameters I am trying to work with?
[[maybe_unused]] means that the function body may not use it, but the signature of the function always have it. Actually event the default value for the boolean does not modify the signature of your function; Thus your function always take 2 arguments, the first being a integer, and the second being a boolean (that may be set to the default if you didn't put it). You end up with calling:
bool forDisplay = true;
preOrderTraversal(/* integer searchData; bool geting casted to int */ forDisplay,
false /* the forDisplay (2nd param) default value*/);
which does not meet your expectations.
[EDIT]
how to overcome?
There is not builtin way to use named parameters in C++ but you may workaround using a helper class:
struct PreOrderTraversal {
bool _forDisplay = false;
int _searchData = 0; /* FIXME What is the default here? */
auto& forDisplay() { _forDisplay = true; return *this; }
auto& searchData(int x) { _searchData = x; return *this; }
void run() { if (_forDisplay) ;//do the right things
else ;// use data
}
};
then you can use it with:
PreOrderTraversal().forDisplay().run();
PreOrderTraversal().searchData(123).run();
This kinda mimics that named parameter feature.

Is there a way to dynamically change the return-type of a function in C++ based on function parameter values?

I am working on a problem that requires me to return different return-types based on my function parameter values that I provide.
I want to do something like this --
In the code below, doSomething() is an already existing function (used by a lot of clients) which takes mode as a function parameter, and returns std::list<ReturnType> already.
Based on the mode value, I had to create another sub-functionality which returns a shared_future<std::list<ReturnType>>.
How can I change this code so that it can return one of the two return types based on the mode value?
Note: ReturnType is a template typename which we are using for the entire class.
Code:
std::shared_future<std::list<ReturnType> > futureValue() {
return functionReturningSharedFuture();
}
std::list<ReturnType> listValue() {
return functionReturningList();
}
std::list<ReturnType> doSomething(int mode) {
if(mode == 1){
// new functionality that I added
return futureValue(); // This (obviously) errors out as of now
}
else{
// already there previously
return listValue();
}
}
int main() {
doSomething(1);
return 0;
}
How can I change this code so that it can return one of the two return types based on the mode value?
Constraints and Issues:
This issue could've been easily solved by function overloading if we provide an extra function parameter (like a true value), but that extra argument is not useful, since we are already using mode. Also, it isn't considered a good design to add variables which have almost no use.
One of the major constraints is that there are clients who are already using this doSomething() expect a std::list<ReturnType>, and so I cannot return boost::any or std::variant or anything similar.
I tried using std::enable_if, but it wasn't working out since we are getting the mode value at runtime.
We can't use template metaprogramming since that would change the way our function is being called on the client-side. Something that we can't afford to do.
Thank you.
This cannot be done.
You can only have one function with a given signature. If you have calling code that already expects this to return a std::list<ReturnType>, that's it; you're done.
If you could guarantee that all existing calling code looks like
auto l = obj.doSomething(1);
then you could potentially change the return type to something which would look like a std::list to any calling code. But if there's any calling code that looks like
std::list<ReturnType> l = obj.doSomething(1);
then that's off the table.
You probably need to rethink your design here.
From the example main, I see doSomething(1);, so maybe at the call site the value of the parameter mode is always known at compile-time. In this case, one option is that you make doSomething a template<int mode> function. I'm thinking about something like this:
#include <iostream>
#include <list>
#include <vector>
// assuming you cannot change this (actually you have changed it in you example, ...)
std::list<int> doSomething(int mode) {
std::cout << "already existing function\n";
return std::list<int>{1,2,3};
}
// then you can put this too
template<int N>
auto doSomething();
template<>
auto doSomething<10>() {
std::cout << "new function\n";
return std::vector<int>{1,2,3};
}
int main() {
auto x = doSomething(3);
auto y = doSomething<10>();
}
Probably another option would be to use a if constexpr intead of if and an auto/decltype(auto) return type in doSomething, but I haven't tried it.

is there a way to store a generic templated function pointer?

The Goal:
decide during runtime which templated function to use and then use it later without needing the type information.
A Partial Solution:
for functions where the parameter itself is not templated we can do:
int (*func_ptr)(void*) = &my_templated_func<type_a,type_b>;
this line of code can be modified for use in an if statement with different types for type_a and type_b thus giving us a templated function whose types are determined during runtime:
int (*func_ptr)(void*) = NULL;
if (/* case 1*/)
func_ptr = &my_templated_func<int, float>;
else
func_ptr = &my_templated_func<float, float>;
The Remaining Problem:
How do I do this when the parameter is a templated pointer?
for example, this is something along the lines of what I would like to do:
int (*func_ptr)(templated_struct<type_a,type_b>*); // This won't work cause I don't know type_a or type_b yet
if (/* case 1 */) {
func_ptr = &my_templated_func<int,float>;
arg = calloc(sizeof(templated_struct<int,float>, 1);
}
else {
func_ptr = &my_templated_func<float,float>;
arg = calloc(sizeof(templated_struct<float,float>, 1);
}
func_ptr(arg);
except I would like type_a, and type_b to be determined during runtime. I see to parts to the problem.
What is the function pointers type?
How do I call this function?
I think I have the answer for (2): simply cast the parameter to void* and the template function should do an implicit cast using the function definition (lease correct me if this won't work as I think it will).
(1) is where I am getting stuck since the function pointer must include the parameter types. This is different from the partial solution because for the function pointer definition we were able to "ignore" the template aspect of the function since all we really need is the address of the function.
Alternatively there might be a much better way to accomplish my goal and if so I am all ears.
Thanks to the answer by #Jeffrey I was able to come up with this short example of what I am trying to accomplish:
template <typename A, typename B>
struct args_st {
A argA;
B argB;
}
template<typename A, typename B>
void f(struct args_st<A,B> *args) {}
template<typename A, typename B>
void g(struct args_st<A,B> *args) {}
int someFunction() {
void *args;
// someType needs to know that an args_st struct is going to be passed
// in but doesn't need to know the type of A or B those are compiled
// into the function and with this code, A and B are guaranteed to match
// between the function and argument.
someType func_ptr;
if (/* some runtime condition */) {
args = calloc(sizeof(struct args_st<int,float>), 1);
f((struct args_st<int,float> *) args); // this works
func_ptr = &g<int,float>; // func_ptr should know that it takes an argument of struct args_st<int,float>
}
else {
args = calloc(sizeof(struct args_st<float,float>), 1);
f((struct args_st<float,float> *) args); // this also works
func_ptr = &g<float,float>; // func_ptr should know that it takes an argument of struct args_st<float,float>
}
/* other code that does stuff with args */
// note that I could do another if statement here to decide which
// version of g to use (like I did for f) I am just trying to figure out
// a way to avoid that because the if statement could have a lot of
// different cases similarly I would like to be able to just write one
// line of code that calls f because that could eliminate many lines of
// (sort of) duplicate code
func_ptr(args);
return 0; // Arbitrary value
}
Can't you use a std::function, and use lambdas to capture everything you need? It doesn't appear that your functions take parameters, so this would work.
ie
std::function<void()> callIt;
if(/*case 1*/)
{
callIt = [](){ myTemplatedFunction<int, int>(); }
}
else
{
callIt = []() {myTemplatedFunction<float, float>(); }
}
callIt();
If I understand correctly, What you want to do boils down to:
template<typename T>
void f(T)
{
}
int somewhere()
{
someType func_ptr;
int arg = 0;
if (/* something known at runtime */)
{
func_ptr = &f<float>;
}
else
{
func_ptr = &f<int>;
}
func_ptr(arg);
}
You cannot do that in C++. C++ is statically typed, the template types are all resolved at compile time. If a construct allowed you to do this, the compiler could not know which templates must be instanciated with which types.
The alternatives are:
inheritance for runtime polymorphism
C-style void* everywhere if you want to deal yourself with the underlying types
Edit:
Reading the edited question:
func_ptr should know that it takes an argument of struct args_st<float,float>
func_ptr should know that it takes an argument of struct args_st<int,float>
Those are incompatible. The way this is done in C++ is by typing func_ptr accordingly to the types it takes. It cannot be both/all/any.
If there existed a type for func_ptr so that it could take arguments of arbitrary types, then you could pass it around between functions and compilation units and your language would suddenly not be statically typed. You'd end up with Python ;-p
Maybe you want something like this:
#include <iostream>
template <typename T>
void foo(const T& t) {
std::cout << "foo";
}
template <typename T>
void bar(const T& t) {
std::cout << "bar";
}
template <typename T>
using f_ptr = void (*)(const T&);
int main() {
f_ptr<int> a = &bar<int>;
f_ptr<double> b = &foo<double>;
a(1);
b(4.2);
}
Functions taking different parameters are of different type, hence you cannot have a f_ptr<int> point to bar<double>. Otherwise, functions you get from instantiating a function template can be stored in function pointers just like other functions, eg you can have a f_ptr<int> holding either &foo<int> or &bar<int>.
Disclaimer: I have already provided an answer that directly addresses the question. In this answer, I would like to side-step the question and render it moot.
As a rule of thumb, the following code structure is an inferior design in most procedural languages (not just C++).
if ( conditionA ) {
// Do task 1A
}
else {
// Do task 1B
}
// Do common tasks
if ( conditionA ) {
// Do task 2A
}
else {
// Do task 2B
}
You seem to have recognized the drawbacks in this design, as you are trying to eliminate the need for a second if-else in someFunction(). However, your solution is not as clean as it could be.
It is usually better (for code readability and maintainability) to move the common tasks to a separate function, rather than trying to do everything in one function. This gives a code structure more like the following, where the common tasks have been moved to the function foo().
if ( conditionA ) {
// Do task 1A
foo( /* arguments might be needed */ );
// Do task 2A
}
else {
// Do task 1B
foo( /* arguments might be needed */ );
// Do task 2B
}
As a demonstration of the utility of this rule of thumb, let's apply it to someFunction(). ... and eliminate the need for dynamic memory allocation ... and a bit of cleanup ... unfortunately, addressing that nasty void* is out-of-scope ... I'll leave it up to the reader to evaluate the end result. The one feature I will point out is that there is no longer a reason to consider storing a "generic templated function pointer", rendering the asked question moot.
// Ideally, the parameter's type would not be `void*`.
// I leave that for a future refinement.
void foo(void * args) {
/* other code that does stuff with args */
}
int someFunction(bool condition) {
if (/* some runtime condition */) {
args_st<int,float> args;
foo(&args);
f(&args); // Next step: pass by reference instead of passing a pointer
}
else {
args_st<float,float> args;
foo(&args);
f(&args); // Next step: pass by reference instead of passing a pointer
}
return 0;
}
Your choice of manual memory management and over-use of the keyword struct suggests you come from a C background and have not yet really converted to C++ programming. As a result, there are many areas for improvement, and you might find that your current approach should be tossed. However, that is a future step. There is a learning process involved, and incremental improvements to your current code is one way to get there.
First, I'd like to get rid of the C-style memory management. Most of the time, using calloc in C++ code is wrong. Let's replace the raw pointer with a smart pointer. A shared_ptr looks like it will help the process along.
// Instead of a raw pointer to void, use a smart pointer to void.
std::shared_ptr<void> args;
// Use C++ memory management, not calloc.
args = std::make_shared<args_st<int,float>>();
// or
args = std::make_shared<args_st<float,float>>();
This is still not great, as it still uses a pointer to void, which is rarely needed in C++ code unless interfacing with a library written in C. It is, though, an improvement. One side effect of using a pointer to void is the need for casts to get back to the original type. This should be avoided. I can address this in your code by defining correctly-typed variables inside the if statement. The args variable will still be used to hold your pointer once the correctly-typed variables go out of scope.
More improvements along this vein can come later.
The key improvement I would make is to use the functional std::function instead of a function pointer. A std::function is a generalization of a function pointer, able to do more albeit with more overhead. The overhead is warranted here in the interest of robust code.
An advantage of std::function is that the parameter to g() does not need to be known by the code that invokes the std::function. The old style of doing this was std::bind, but lambdas provide a more readable approach. Not only do you not have to worry about the type of args when it comes time to call your function, you don't even need to worry about args.
int someFunction() {
// Use a smart pointer so you do not have to worry about releasing the memory.
std::shared_ptr<void> args;
// Use a functional as a more convenient alternative to a function pointer.
// Note the lack of parameters (nothing inside the parentheses).
std::function<void()> func;
if ( /* some runtime condition */ ) {
// Start with a pointer to something other than void.
auto real_args = std::make_shared<args_st<int,float>>();
// An immediate function call:
f(real_args.get());
// Choosing a function to be called later:
// Note that this captures a pointer to the data, not a copy of the data.
// Hence changes to the data will be reflected when this is invoked.
func = [real_args]() { g(real_args.get()); };
// It's only here, as real_args is about to go out of scope, where
// we lose the type information.
args = real_args;
}
else {
// Similar to the above, so I'll reduce the commentary.
auto real_args = std::make_shared<args_st<float,float>>();
func = [real_args]() { g(real_args.get()); };
args = real_args;
}
/* other code that does stuff with args */
/* This code is probably poor C++ style, but that can be addressed later. */
// Invoke the function.
func();
return 0;
}
Your next step probably should be to do some reading on these features so you understand what this code does. Then you should be in a better position to leverage the power of C++.

Write method with trailing return type to change based on method call?

I have a class titled Eclipse with a private struct member containing ~30 fields of various data types.
I have a method that will return a data field from the struct, based on a field number passed in as a parameter.
Seeing as the struct contains data of various types, I opted to use the auto keyword with a trailing return type based on a templated parameter. My method header is below.
template<typename TheType>
auto getColumnData(TheType toGet, int fieldNum) -> decltype(toGet) {
// switch statement to return fields based on fieldNum
}
If I want to return a column that is an int, I call getColumnData(0, 1);. The first parameter is only used to determine the return type of the method, and the second parameter determines the field number to return to the method caller.
Theoretically, this would cause the return type of getColumnData() to be int and return the first column (corresponding to the first field) of the struct. But I'm receiving this compilation error:
no viable conversion from returned value of type 'std::string' (aka 'basic_string<char, char_traits<char>, allocator<char> >') to function return type 'decltype(toGet)' (aka 'int')`
I understand that if I were to call this method with an int as the first parameter, and a field number that corresponds to a field returning a std::string, there would be issues. But, based on checks in other classes, this case would never occur.
Is there any way that I can force my compiler to accept this code, even if it might not be correct for certain cases?
I know that I could just overload the method, but I'd rather not have multiple different methods for basically the same purpose if I can figure out how to accomplish the task in only one.
Also, if my understanding of any of this information seems incorrect, please let me know. I'm very new to C++, so I'm just learning these features as I go.
You cannot change a method's return type dynamically at runtime like you are attempting to do. Your first parameter is not a data type known at compile-time. It is just an integer that is populated at runtime, so you can't make compile-time decisions based on it at all.
A simple solution would be to use std::variant (C++17 or later) or boost::variant (C++11 and later) as the return type:
using FieldType = std:::variant<int, std::string>;
FieldType getColumnData(int fieldNum) {
// switch statement to return fields based on fieldNum
}
int i = std::get<int>(getColumnData(1));
std::string s = std::get<std::string>(getColumnData(2));
Otherwise, you would have to make the return type be a template parameter, not a method parameter:
template<typename TheType>
TheType getColumnData(int fieldNum) {
// switch statement to return fields based on fieldNum
}
But then you run into the problem that not all fields will be convertible to the return type (can't return a std::string field when an int is requested, etc), so you can't just switch on the fieldNum since it is not evaluated at compile-time.
You might be tempted to make the field number be a template parameter so it is constant at compile-time, and then specialize on it:
template<const int FieldNum>
auto getColumnData() { return 0; };
template<> int getColumnData<1>() { return private_struct.Field1; }
template<> std::string getColumnData<2>() { return private_struct.Field2; }
// etc...
int i = getColumnData<1>();
std::string s = getColumnData<2>();
But I get errors when I try to do that on a templated class method ("explicit specialization in non-namespace scope").
You might be tempted to do something like this, and hope the compiler optimizes away the unused branches:
template<const int FieldNum>
auto getColumnData() {
if (FieldNum == 1) return private_struct.Field1;
if (FieldNum == 2) return private_struct.Field2;
//etc...
return 0;
}
or
template<const int FieldNum>
auto getColumnData()
{
switch (FieldNum) {
case 1: return private_struct.Field1;
case 2: return private_struct.Field2;
// etc...
}
return 0;
};
int i = getColumnData<1>();
std::string s = getColumnData<2>();
But that doesn't work, either ("inconsistent deduction for auto return type" errors).