Consider the code:
void fnc(int, long, double*){}
template<int I> void f(int, long, double*){}
int main()
{
bool a = fnc; //(1) ok
bool b = f<4>; //(2) error
}
It triggers an error:
error: cannot resolve overloaded function 'f' based on conversion to type 'bool'
bool b = f<4> //(2) error
Why first case is correct, but second case isn't correct?
You are totally neglecting all the warnings, which are there to tell you that you're doing something very wrong.
Besides, you should use the & to get the function address.
Secondly, you're implicitly casting a function pointer to a bool variable.
Cast it explicitly to tell the compiler that you think you know what you're doing and you're sure about it:
bool b= (void*)&ff<4>;
I just have to say that casting stuff to avoid errors and warning is a bad idea.
In most cases the warnings and errors are there to help you avoid loss of data and things that usually do cause runtime errors.
Related
In the following case I try to cast a pointer to a struct into a pointer to another struct (which has the same memory layout behind the scenes). I try to do this in a const correct way, however the compiler is complaining.
I looked at a similar issue but I need the constness to propagate and it doesn't work like described for me.
Demo
struct queue
{
// ...
};
typedef struct queue* queue_handle;
struct dummy_queue
{
// ...
};
struct queue_wrapper
{
auto get_queue() const -> queue_handle {
return reinterpret_cast<const queue_handle>(&d);
}
dummy_queue d;
};
int main()
{
queue_wrapper w;
w.get_queue();
}
Error:
<source>: In member function 'queue* queue_wrapper::get_queue() const':
<source>:17:16: error: 'reinterpret_cast' from type 'const dummy_queue*' to type 'queue_handle' {aka 'queue*'} casts away qualifiers
17 | return reinterpret_cast<const queue_handle>(&d);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I'm converting to a const pointer though (which gcc seems to misunderstand somehow). I do not need to change the pointer after returning it. How do I accomplish this conversion without errors?
const queue_handle applies the const to the pointer type itself, not the pointed to type as you intent to.
I would suggest adding a const_queue_handle alias to const queue* if you are already using aliases for the pointers (whether or not that is a good idea is a matter of opinion) and then you can use that as template argument to reinterpret_cast.
Also beware that even if the struct layout is identical, this is still undefined behavior territory. A compiler may assume that a pointer to one of the struct types won't alias one to the other and use that for optimization. You should probably at least compile everything with -fno-strict-aliasing when doing this.
I had to use pointers to member functions in various circumstances before. Typically, I used mem_fun. However, this is the first time I am trying to use it on a member template that returns auto. It does work for auto return 'type' if the member is not a template and it does work for a member template if the return type is specified. Also, I tried passing the expected types directly into mem_fun() and it did not help.
Any alternative solutions that do not rely on mem_fun() will also be appreciated.
Below is the code that does not compile due to the following error:
no matching function for call to 'mem_fun()'.
It should be noted that if auto is replaced by int the code compiles. Also, if auto is left, but template<int N> and <1> , the code also compiles and works as expected.
class Q
{
public:
int myq;
template<int N>
auto mymethod(int a)
{
std::cout << myq*a << std::endl;
}
void setint(int a)
{
myq = a;
}
};
int main()
{
boost::function<void (int)> p_member;
Q q;
p_member = std::bind1st(
std::mem_fun(
&Q::mymethod<1>
),
&q
);
q.setint(1);
p_member(100);
//...
}
This is not really specific to auto, it's a general limitation of GCC. There are situations where it just does not realise that if after specifying template arguments there is only one possible function it could refer to, it refers to that function. For most code, it doesn't matter, and for most situations where it does matter, GCC has worked around those limitations, but sometimes it does come to the surface. Quite a while ago I reported a similar issue:
template <int> void f() {}
int main() { return f<0> != f<0>; }
This should compare the address of f<0> with the address of f<0>, so should return zero, but GCC cannot figure out that f<0> is not overloaded, and complains with:
error: invalid operands of types ‘<unresolved overloaded function type>’ and ‘<unresolved overloaded function type>’ to binary ‘operator!=’
Here, a workaround is adding a pointless no-op that convinces the compiler to try a bit harder in figuring out the type: return &f<0> != &f<0>; does work.
A similar approach can also be used for your code. Although the & operator cannot be added here, other no-ops do work:
p_member = std::bind1st(
std::mem_fun(
true ? &Q::mymethod<1> : nullptr
),
&q
);
I see no reason for thinking your code might be invalid. It's accepted as it is by other compilers (at least clang), and if it were invalid, then surely my workaround here would be invalid for the exact same reason.
I have a function
void foo(int *bar)
{}
Visual Studio 2012 will now happily and without warnings compile if I call foo like this:
int main()
{
foo(false);
return 0;
}
If I however change foo(false) to foo(true) than I get an error:
1>main.cpp(132): error C2664: 'foo' : cannot convert parameter 1 from 'bool' to 'int *'
1> Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast
Any idea how I can make sure that I get an error when passing false, too? My only idea is to add a second private function "void foo(bool bar)". Then I indeed get the desired error stating that foo(bool bar) is private. But this only works when foo is called from outside the class and it clutters my interface.
First, as to why it accepts false but not true: The literal false will be interpreted as the integral 0 and a literal 0 will convert to a null pointer of any type. true on the other hand cannot be converted to a pointer type as it converts to an integral 1.
As to how to solve your problem: Your approach with an extra bool overload will work fine for both public and non-public callers as long as you don't implement the private overload. In that case public callers will get a compile error and member callers will get a linker error.
However, you may wish to consider additional things as well.
Does your function need to accept null pointers? If not, change it to accept by reference instead and the problem just goes away.
If your function really does need to accept null pointers then I would suggest in this case to just trust your users to call it correctly instead of cluttering your interface trying to prevent every possible misuse.
In C++11, you may write:
void foo(bool) = delete; // cannot be use by anybody (class itself included).
As vs2012 doesn't support = delete,
You may try this hack using SFINAE:
template <typename T>
typename std::enable_if<std::is_same<T, int>::value, void>::type
foo(T* t);
With the old C++98 way 'private without implementation':
private: // Fail to compile from outside
void foo(bool); // No implementation -> fail to link time if internally used.
You can wait for C++17, when Concepts can be used anywhere auto is in C++11, and write your signature as:
void foo( IsActually<int*>::template test x ) { }
... which actually looks pretty bad, but they may clean up the syntax by then.
Given a template pass-by-reference conversion/type-cast operator (without const) is possible:
class TestA
{
public:
//Needs to be a const return
template<typename TemplateItem>
operator TemplateItem&() const {TemplateItem A; A = 10; return A;}
};
int main()
{
TestA A;
{
int N;
N = A;
printf("%d!\n",N);
}
{
float N;
N = A;
printf("%f!\n",N);
}
return 0;
}
And given the following code (with const):
class TestA
{
public:
//Produces error
template<typename TemplateItem>
operator const TemplateItem&() const {TemplateItem A; A = 10; return A;}
};
Produces these errors:
error: cannot convert 'TestA' to 'int' in assignment
error: cannot convert 'TestA' to 'float' in assignment
Question
How do I make it so the conversion/type-cast operator return a const pass-by-reference of the template type?
Context
Before most people come in and freak about how 'you can't convert it to just anything', you'll need context. The above code is pseudo code - I'm only interested on const reference returns being possible, not the pitfalls of a templated conversion function. But if you're wondering what it's for, it's relatively simple:
TemplateClass -> Conversion (turned into byte data) -> File
TemplateClass <- Conversion (changed back from byte data) <- File
The user is expected to know what they are getting out, or it's expected to be automated (I.E. saving/loading states). And yes, there is a universal method for templates using pointers to convert any type into byte data.
And don't give me claptrap about std doing this sort of thing already. The conversion process is part of a more complicated class library setup.
I'm a programmer. Trust me. C++ trusts me and lets me make mistakes. Only way I'll learn.
Firstly, your conversion operator is already undefined behavior because you return a reference (const or not) to a local variable that has gone out of scope. It should work fine if you change your conversion operator to return by value which won't induce UB.
EDIT: (removed incorrect information about conversion operators).
But are you really sure that you really want your class type to be convertible to anything? That seems like it's just going to cause many headaches in the future when you're maintaining the code and it converts to an unexpected type automatically.
Another possible implementation is to create an as template method that basically does what your conversion operator wants to do and call it like obj.as<int>().
The following is a common typo with language newcomers, who think that they are defining an object but are actually declaring a function:
struct T
{
void foo() {}
};
int main()
{
T obj();
obj.foo();
}
GCC 4.1.2's error is:
In function 'int main()':
Line 9: error: request for member 'foo' in 'obj', which is of non-class type 'T ()()'
compilation terminated due to -Wfatal-errors.
Why is the reported type in the message T ()()? I'd have expected T ().
IIRC this is just a compiler bug. GCC 4.4 says T() while 4.2 says T()() for me.
The error is best understood when you realize that you usually don't write out function types without naming at least the function, but it's a bit more common for function pointers.
For instance, int (*fooPtr)() names the pointer. If you omit the name, you have int (*)(). Now, going from function pointer to function type would give you int ()().
There's no real standard here, because ISO C++ doesn't define canonical names for all types. For instance, const volatile int is the same type as volatile const int, and neither form is canonical.