A similar question to this
C++ Function Overloading Similar Conversions
has been asked and i understand the general premise of the problem. Looking for a solution.
I have 2 overloaded functions:
virtual IDataStoreNode* OpenNode(const char *Name, bool bCreateIfNotExist,int debug=0) { return 0;
}
virtual IDataStoreNode* OpenNode(const char* Name,int debug=0) const { return 0; }
From the errors it would appear that bool and int cannot be used to distinguish function overloads.
The question is , is there a way to work around this?
bool and int can be used to distinguish function overloads. As one would expect, bool arguments will prefer bool overloads and int arguments - int overloads.
Judging by the error message (I assume that the title of your question is a part of the error message you got), what you are dealing with is the situation when the argument you supply is neither bool nor int, yet conversions to bool and int exist and have the same rank.
For example, consider this
void foo(bool);
void foo(int);
int main() {
foo(0); // OK
foo(false); // OK
foo(0u); // ERROR: ambiguous
}
The first two calls will resolve successfully and in expected manner. The third call will not resolve, because the argument type is actually unsigned int, which however supports implicit conversions to both bool and int thus making the call ambiguous.
How are you calling your functions? Show us the arguments you are trying to pass.
For the following functions:
virtual IDataStoreNode* OpenNode(const char *Name, bool bCreateIfNotExist,int debug=0) { return 0; }
virtual IDataStoreNode* OpenNode(const char* Name, int debug=0) const { return 0; }
The following call (as an example, there might be others) would be ambiguous:
unsigned int val = 0; //could be double, float
OpenNode("", val);
Since a unsigned int can be converted to both bool and int, there is ambiguity. The easiest way to resolve it is to cast the parameter to the type of the parameter in your preferred overload:
OpenNode("", (bool)val);
OR
OpenNode("", (int)val);
Related
As the title reads.
I have many other functions using the included method function, just doesn't seem to like this one.
Any help is appreciated.
Also excuse my probably incorrect terminology. I'm terrible with it.
Error 1
Error 2
Error
unsigned long Create_Font() noexcept
{
using Create_Font = void(__thiscall*)(void*);
return method<Create_Font>(66, this)(this);
}
Method Function
template<typename out,class type>
inline out method(size_t index, type* self) noexcept
{
return reinterpret_cast<out>((*reinterpret_cast<void***>(self))[index]);
}
Your Create_Font type is declared as returning void:
using Create_Font = void(__thiscall*)(void*);
// ^-- returns void
But your Create_Font function is defined as returning unsigned long:
unsigned long Create_Font() noexcept {
// ^-- returns unsigned long
/* ... */
}
So your compiler will complain on return method<Create_Font>(66, this)(this);, because the result of method<Create_Font>(66, this)(this) is void, but the function needs to return an unsigned long.
(and there's no sensible way to "convert" void into unsigned long)
a simple and I guess easy to answer question (if I did not already got it myself). The following overloaded functions:
void BR(const bool set) { backwardReaction_[nReac_] = set; }
bool BR(const int reactionNumber) const { return backwardReaction_[reactionNumber]; }
The first function is a setter and the second a getter function. backwardReaction_ is of type std::vector<bool>. The problem occurs whenever I want to call the second function. Here I get a compiler error overload function BR(xy) ambigious.
int main()
.
.
const int i = 3;
bool a = chem.BR(i);
The compiler error is equal to:
chemistryTestProg.cpp: In function ‘int main()’:
chemistryTestProg.cpp:74:34: error: call of overloaded ‘BR(const int&)’ is ambiguous
const bool a = chem.BR(i);
^
In file included from ../../src/gcc/lnInclude/chemistryCalc.hpp:38:0,
from ../../src/gcc/lnInclude/chemistry.hpp:38,
from chemistryTestProg.cpp:35:
../../src/gcc/lnInclude/chemistryData.hpp:266:18: note: candidate: void AFC::ChemistryData::BR(bool)
void BR(const bool);
^~
../../src/gcc/lnInclude/chemistryData.hpp:322:22: note: candidate: bool AFC::ChemistryData::BR(int) const
bool BR(const int) const;
^~
I guess that I get the problem because of the types bool and int which are identically (true => int(1), false => int(0). As I am changing the getter name to, e.g., bool getBR(const int reactionNumber) {...} everything works fine. So I guess the problem is about the similarities of the bool and int treatment within c++. I also tried a variety of different calls such as:
const bool a = chem.BR(4)
const bool a = chem.BR(int(5))
const bool a = chem.BR(static_cast<const int>(2))
bool a = chem.BR(...)
Thus, I think it is really related to the bool andint overloading arguments. Nevertheless, I made a quick search and did not find too much about these two overload types and resulting problems. Tobi
This is because you declared BR(int), but not BR(bool), to be const. Then when you call BR(int) on a non-const object, the compiler has two conflicting matching rules: parameter matching favours BR(int), but const-ness matching favours BR(bool).
I want to write a template function to copy data from one array to another array. I only want to handle int, double and char* (string) arrays in my program.
template<typename T>
void copy_key(T *destination, int destination_index, T *source, int source_index){
if (typeid(T) == typeid(int) or typeid(T) == typeid(double)){
destination[destination_index] = source[source_index];
} else {
// char* case
strcpy(destination[destination_index], source[source_index]);
}
}
If I call copy_key() as below, I will get error : Cannot initialize a parameter of type 'char*' with an lvalue of type 'double'.
int main(int argc, const char * argv[]) {
double from_array[3] = {1.0,2.0,3.0};
double to_array[3];
copy_key(to_array, 0, from_array, 2);
std::cout << to_array[0] << std::endl;
return 0;
}
I thought if T was double, the else block would not be entered. My question is how to correctly use condition on the template type in my example?
I thought if T was double, the else block would not be entered.
You thought correctly. But your assumption about its consequences are not correct.
Just because some code will not be executed, doesn't mean that it, along with the rest of the program, doesn't need to be well formed.
Even though in this case it might be possible for the compiler to prove that the line will not be executed, such proof is practically impossible for all possible programs in general, so it cannot affect the correctness of the program.
A typical solution is to use either overloads, or template specializations:
void copy_key(char *destination, int destination_index, const char *source, int source_index){
strcpy(...);
}
void copy_key(double *destination, int destination_index, double *source, int source_index){
destination[destination_index] ...
}
In the upcoming C++17, there will be constexpr if which allows conditionally compiled blocks within a single function.
In C++17 you will get if constexpr that only evaluates one branch of the if-statement.
Right now both the if-part and the else-part must be valid code for type T. If you want it to behave different for different types, you will have to specialize the template.
In C++14 and before, use template specialization instead of conditionals.
C++ is a compiled language, not interpreted. When a templatized function is being compiled for a particular concrete use, the entire function needs to be compiled, not just the branches that happen to be taken. The compiler in general can't infer the exact path your code will take for all inputs a priori.
template<typename T>
void copy_key(T *destination, int destination_index, T *source, int source_index){
destination[destination_index] = source[source_index];
}
template<>
void copy_key(const char** destination, int destination_index, const char** source, int source_index) {
// char* case
strcpy(destination[destination_index], source[source_index]);
}
No, you can´t. Put as:
template<typename T>
void copy_key(T *destination, int destination_index, T *source, int source_index){
if (some_condition){ // some_condition met
destination[destination_index] = source[source_index];
} else { // some condition not met
// char* case
strcpy(destination[destination_index], source[source_index]);
}
}
is easier to see.
You need a "conditional compilation" instead (template specialization)
I am trying to pass parameters to a function pointer being passed as a parameter.
Code:
void Test(wchar_t* a, wchar_t* b)
{
// ...
}
void Test2(void(*Func)(wchar_t*, wchar_t*))
{
// ...
}
int main()
{
Test2(Test(L"Hello", L"Testing"));
return 0;
}
I am getting this error:
argument of type "void" is incompatible with parameter of type "void (*)(wchar_t *, wchar_t *)"
How do I fix this to accomplish what I'm trying to achieve?
Edit: Sorry for not being clear. What I'm actually trying to accomplish is inject a function into a child process and pass two parameters (wchar_t*, wchar_t*) so I can use them. But the main function can either be void or int argc, char** argv. So I accomplished what I'm trying to achieve by simply using global variables
You probably want to have something like
void Test2(void(*Func)(wchar_t*, wchar_t*),wchar_t* x, wchar_t* y)
{
(*Func)(x,y);
}
int main()
{
Test2(Test,L"Hello", L"Testing");
return 0;
}
instead.
As for your comment
How do i do this in C++ with templates?
I could think of
template<typename Param>
void Test2(void(*Func)(Param, Param), Param x, Param y) {
(*Func)(x,y);
}
void Test(wchar_t* a, wchar_t* b);
int main() {
Test2(Test,L"Hello", L"Testing");
return 0;
}
This should just work fine.
There are more than one way to fix tihs issue, however, let me just try to show why this error is occuring.
Every function has a type of value associated with it. This means, that every function evaluates to a value of some type. This is indicated by its return value.
For example:
int foo(/*whatever*/);
evaluates to an int. So foo(/*whatever*/) can be used anywhere an int is expected. For example like int a = b + foo(/*whatever*/).
Simlarly float bar(/*whatever*/); evaluates to a float, hence bar(/*whatever*/) can be used anywhere a float is expected. For example like float a = b + bar(/*whatever*/).
A function that returns void like void foobar(/*whatever*/) however, evaluates to void and cannot be used where a value of some type (say int, float, etc) is expected.
Now coming to code. This line in your main function has the issue:
int main()
{
Test2(Test(L"Hello", L"Testing")); /* Issue here */
return 0;
}
Here you are passing Test(L"Hello", L"Testing") as the argument to Test2. Now remember, that Test(/*whatever*/), evaluates to a void because Test returns a void.
So what you are doing in that line is something like
Test2(/*something that evaluates to a void*/);
However, Test2 expectes a void (*)(wchar_t*, wchar_t*), which is a pointer to a function that returns void, which is different from void.
So what is happening, is that the compiler is seeing that you are passing a void in a place where a void (*) (wchar_t*, wchar_t*) is expected, so it is correctly indicating that error.
There can be different ways to solve this issue which are mentioned in other answers.
Do I need to use C++ templates?
Of course, you can do that using C++ templates as it follows:
#include<utility>
// ...
template<typename F, typename... A>
void Test2(F &&f, A&&... a)
{
std::forward<F>(f)(std::forward<A>(a)...);
// ...
}
// ...
Test2(Test, L"Hello", L"Testing");
But you don't need them to do what you are trying to do.
#πάνταῥεῖ has already explained why in its answer.
I have two functions with a little different functionality, so I can't make them as template functions.
int func64(__int64 a) {
return (int) a/2;
}
int func32(int a) {
return a--;
}
Depending on variable b64, I would like to call func64 or func32. I don't want check if b64 is true many times in my code, so I use pointers to functions.
void do_func(bool b64) {
typedef int (*pfunc32)(int);
typedef int (*pfunc64)(__int64);
pfunc32 call_func;
if (b64)
call_func = func64; //error C2440: '=' : cannot convert from 'int (__cdecl *)(__int64)' to 'pfunc32'
else
call_func = func32;
//...
call_func(6);
}
How can I avoid this error and cast call_func to pfunc32 or pfunc64?
The language requires all functions called through the same function pointer to have the same prototype.
Depending on what you want to achieve, you could use the pointer/cast aproach already mentioned (which satisfies this requirement at the loss of type safety) or pass a union instead:
union u32_64
{
__int64 i64;
int i32;
};
int func64(union u32_64 a) {
return (int) a.i64/2;
}
int func32(union u32_64 a) {
return --a.i32;
}
void do_func(bool b64) {
typedef int (*pfunc)(union u32_64);
pfunc call_func;
if (b64)
call_func = func64;
else
call_func = func32;
//...
union u32_64 u = { .i64 = 6 };
call_func(u);
}
Pass a void pointer and cast it in the function body.
Of course this means less compiler control if you use the wrong type; if you call func64 and pass an int to it the program will compile and produce wrong results without giving you any tip of what is going wrong.
int func64(void *a) {
__int64 b = *((__int64*) a);
return (int) b/2;
}
int func32(void *a) {
int b = *((int *) a)
return b-1;
}
I need to call func32() or func64() depending on flag b64
So do that:
void do_func(bool b64) {
if (b64)
func64(6);
else
func32(6);
}
Well, first of all, please note that function func32 is returning the input argument as is.
This is because with return a--, you are returning the value of a before decrementing it.
Perhaps you meant to return a-1 instead?
In any case, you can simply declare this function as int func32(__int64 a).
This way, it will have the same prototype as function func64, but will work exactly as before.
BTW, calling a function through a pointer might be more "expensive" than a simple branch operation, so depending on your application, you might be better off with a simple if/else conditional statement...
Make a wrapper for func64:
int func64_as_32(int a) {
return func64(a);
}
Now you can assign either func32 or func64_as_32 to call_func since they have the same signature. The value you pass in, 6, has type int so passing it to func64_as_32 has the same effect as passing it directly to func64.
If you have call sites where you pass in a value of type __int64 then you'd do it the other way around, wrap func32.
As bool in C++ converts to int ( true => 1, false => 0 ) you can use b64 as array index. So take SJuan76's advice, convert your functions prototype to int f(void*) and put them into array int (*array_fun[2])(void* x); . You can call these functions then like that :
int p = 6;
array_fun[b64](&p);