Please take a look at this code and run it:
I'm getting very strange error:
Error 1 error C2663: 'Allocator::allocate_help' : 2 overloads have no legal conversion for 'this' pointer
template<class FailureSignal>
class Allocator
{
private:
template<class Exception,class Argument>
void allocate_help(const Argument& arg,Int2Type<true>)
{
}
template<class Exception,class Argument>
std::nullptr_t allocate_help(const Argument& arg,Int2Type<false>)
{
return nullptr;
}
public:
template<class T>
void Allocate(signed long int nObjects,T** ptr = 0)const
{
allocate_help<std::bad_alloc>(1,Int2Type<true>());
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Allocator<int> all;
all.Allocate<int>(1);
return 0;
}
I absolutely do not understand this err msg. Hope someone can help me with this. Thank you.
I noticed Allocate is declared const but allocate_help is not - could that be related to the issue?
I had the same error which was also caused by const but in a bit different way.
I have two virtual functions (overloads), one was const and the other was not. This was causing the problem. Turns out if you want to overload a function, they both need to match if they are const or not.
virtual void value() const = 0;
virtual void value(MyStruct & struct) = 0;
The above code will cause this error. The fix is to change declaration of 2nd to:
virtual void value(MyStruct & struct) const = 0;
I had this problem, when i tried to change member data in a const declared method.
As we all know, const methods are supposed not to change member data.
The compiler gcc/clang doesn't return good error message.
It successfully compiled after removing const specifier from
void I_am_a_const_method_but_trying_to_modify_member() const{
amap.emplace(std::make_tuple(1, 1, "a"), 1);
}
compiler explorer link
Related
I have a delima. I'm using wrapper classes for native types, however, when using the wrapper types as function arguments, the implicit conversion for char pointer to bool keeps causing the compiler to issue an ambiguous function call error:
class VBool
{
public:
VBool(bool b):value(b){}
template<class T>
VBool(T)=delete;
private:
bool value;
};
class VString
{
public:
VString(const char* str):value(str){}
private:
std::string value;
};
void processVType(VBool vb){}
void processVType(VString vs){}
int main()
{
processVType(""); // rejected as ambiguous by compiler.
return 0;
}
Now the compiler allows:
VBool b = true;
And correctly rejects:
VBool b = "string";
But how do I get the compiler to correctly identify the intended function version to be called?
Note: I'm using VCC compiler with language standard for C++17 enabled.
Add another function with proper parameter.
inline void processVType(const char* vs) { processVType(VString(vs)); }
Just out of curiosity, why are you trying to implement something like this?
Following code does not compile in g++7.2.0
template <class Internal>
class Request {
int content = 0;
public:
friend void setContent(int i, void *voidptr) {
Request<Internal> *ptr = (Request<int>*)voidptr;
ptr->content = i;
}
int getContent() {return content;}
};
int main() {
Request<int> req;
setContent(4, &req);
return req.getContent();
}
With error
test.cpp: In instantiation of ‘void setContent(int, void*)’:
test.cpp:14:23: required from here
test.cpp:7:14: error: use of local variable with automatic storage from containing function
ptr->content = i;
~~~~~^~~~~~~
test.cpp:6:28: note: ‘Request<Internal>* ptr’ declared here
Request<Internal> *ptr = (Request<int>*)voidptr;
I don't understand what is wrong with this (apart from being stupid example). Clang 4.0.1 seems to accept it and I am pretty sure it compiled under g++ 5.4
Also: if I remove all templates, this compiles ok.
Is this bug in compiler or I violate some rule I don't know?
EDIT
It seems it stopped working beginning with gcc 7.x https://godbolt.org/g/D6gqcF
I don't know whether GCC is legitimately balking at this construction, but it seems like the total lack of Request<Internal> in the type of setContent is confusing it. The only reason you can refer to Request<Internal> is the injected class name, that comes from the scope of the definition.
template <class Internal>
class Request {
int content = 0;
public:
friend void setContent(int i, void *voidptr); // shouldn't make a difference
int getContent() {return content;}
};
void setContent(int i, void * voidptr)
{
// Where does Internal come from?
Request<Internal> *ptr = (Request<Internal>*)voidptr;
ptr->content = i;
}
I don't think you want a template here, because if you instantiate it with a second type you violate the one definition rule.
class RequestBase {
int content = 0;
public:
virtual ~RequestBase() = default;
friend void setContent(int i, RequestBase * ptr) {
ptr->content = i;
}
int getContent() {return content;}
};
If there are other members of your class, which use Internal, you can add them with a template subclass
template <class Internal>
class Request : public RequestBase {
// members involving Internal
};
The other alternative is that you use Internal in the arguments to setContent
template <class Internal>
class Request {
Internal content = 0;
public:
friend void setContent(Internal i, void *voidptr){
Request<Internal> *ptr = (Request<Internal>*)voidptr;
ptr->content = i;
}
Internal getContent() {return content;}
};
or
template <class Internal>
class Request {
int content = 0;
public:
friend void setContent(int i, Request<Internal> *ptr) {
ptr->content = i;
}
int getContent() {return content;}
};
note that you can still bind void setContent(int, Request<Internal> *) to a void (*)(int, void *) function pointer etc
This one looks genuinely tricky. Let's look at the line again:
Request<Internal> *ptr = (Request<int>*)voidptr;
Those are two different types. How do you convert between one type and another? Well, the obvious way would be a derived-to-base conversion.
Now, you may say that Request<int> is not a derived class. If we look at the whole program, that's true. But in the first phase of template compilation, the compiler hasn't seen any template specializations yet. There may still be a specialization of Request<int> that could introduce a base class later down the road (!)
I'd have to grab appropriate C++ standards to check is something subtle changed in this area, but from an engineering point is comes as no surprise when such code proves fragile in the face of minor compiler changes.
I'm implementing a class that performs type erasure for small objects and have encountered a segmentation fault which I do not understand.
The following program:
#include <iostream>
#include <type_traits>
struct small_object
{
public:
template<class T>
small_object(const T& value)
{
new(&storage_) concrete<T>(value);
}
~small_object()
{
get_abstract().~abstract();
}
void print() const
{
// XXX crash here
get_abstract().print();
}
private:
struct abstract
{
virtual ~abstract(){}
virtual void print() const = 0;
};
template<class T>
struct concrete
{
concrete(const T& value) : value_(value) {}
void print() const
{
std::cout << value_ << std::endl;
}
T value_;
};
abstract& get_abstract()
{
return *reinterpret_cast<abstract*>(&storage_);
}
const abstract& get_abstract() const
{
return *reinterpret_cast<const abstract*>(&storage_);
}
typename std::aligned_storage<4 * sizeof(void*)> storage_;
};
int main()
{
small_object object(13);
// XXX i expect this line to print '13' to the terminal but it crashes
object.print();
return 0;
}
Crashes at the lines indicated by XXX.
I believe the issue is that the virtual call to .print() is not being dynamically dispatched correctly, but I don't understand why.
Can anyone tell what am I missing?
You didn't derive concrete<T> from abstract, so no vtable is being created when you construct the object using placement new. Therefore, when you try to invoke the virtual function, it will fail; concrete<T> and abstract are actually completely unrelated types in this example.
I would recommend using the override keyword if you're using C++11 or newer to allow the compiler to generate an error in cases like this.
std::aligned_storage<4 * sizeof(void*)> storage_;
This creates storage of one byte.
The template argument does not set the size of the declared object, but rather the size of an object that can be allocated in a suitably-sized array of this type. Hence, you need
std::aligned_storage<4 * sizeof(void*)> storage_[4 * sizeof(void*)];
GCC 6.2.0 warns you about this:
warning: placement new constructing an object of type ‘small_object::concrete<int>’ and size ‘16’ in a region of type ‘std::aligned_storage<32ul>’ and size ‘1’ [-Wplacement-new=]
(You still need to derive concrete from abstract).
I was pointed to the 'safe bool idiom', and after trying to decipher what is going on (the explanation supplied on the site was not sufficient enough to grant me understanding of why it works), I decided to try to take the following code apart and make an attempt at simplifying it as much as possible. The site supplied code below:
class Testable {
bool ok_;
typedef void (Testable::*bool_type)() const;
void this_type_does_not_support_comparisons() const {}
public:
explicit Testable(bool b=true):ok_(b) {}
operator bool_type() const {
return ok_==true ?
&Testable::this_type_does_not_support_comparisons : 0;
}
};
I decided to analyse the key basis of 'bool_type' given this seems to be what it's centred on. Given the following line:
typedef void (Testable::*bool_type)() const;
One can (not so easily, due to bracketing) deduce it's a typedef of a type of 'void Testable::*', of which bool_type represents. This can be further demonstrated by making the following modifications and function calls:
class Testable {
bool ok_;
typedef void (Testable::*bool_type)() const;
void this_type_does_not_support_comparisons() const {}
public:
explicit Testable(bool b=true):ok_(b) {}
bool_type Test; //Added this
operator bool_type() const {
return ok_==true ?
&Testable::this_type_does_not_support_comparisons : 0;
}
};
int main()
{
Testable Test;
int A = Test.Test; //Compiler will give a conversion error, telling us what type .Test is in the process
}
It allows us to see what type bool_type is:
error: cannot convert 'void (Testable::*)()const' to 'int' in initialization
Which shows it is indeed a type of 'void (Testable::*)'.
The issues crops up here:
If we modify the following function:
operator bool_type() const {
return ok_==true ?
&Testable::this_type_does_not_support_comparisons : 0;
}
And turn it into:
operator void Testable::* () const //Same as bool_type, right?
{
return ok_==true ?
&Testable::this_type_does_not_support_comparisons : 0;
}
It generates the following complaints:
error: expected identifier before '*' token
error: '< invalid operator >' declared as function returning a function
My questions are thus:
Why is it generating those complaints if 'void (Testable::*) is indeed the typedef for bool_type?
And
What is going on here?
Your reasoning goes wrong about here
operator void Testable::* () const //Same as bool_type, right?
This isn't correct. The type of bool_type is, as the compiler tells us in the error message:
'void (Testable::*)()const'
So, to replace it in the operator, you would need something like
operator (void (Testable::*)() const) () const
if that is ever possible! See why even the ugly typedef is an improvement?
In C++11 we also have the new construct explicit operator bool() to save us from this ugliness.
I haven't used void* and const_correctness before so I am not understanding what I am doing wrong in the below code. All I want is to cast a void* returned by a member function of a const object to int*. Please suggest better approaches. Thank you.
I get the following error
passing 'const MyClass' as 'this' argument of 'void* MyClass::getArr()' discards qualifiers
So here's the actual program that I had problem with
class MyClassImpl{
CvMat* arr;
public:
MyClassImpl(){arr = new CvMat[10];}
CvMat *getArr(){return arr;}
};
class MyClass{
MyClassImpl *d;
public:
const void *getArr()const{ return (void*)d->getArr(); }
};
void print(const MyClass& obj){
const int* ptr = static_cast<const int *>(obj.getArr());
}
int main(){
MyClass obj1;
print(obj1);
}
Only the methods such as 'print()' in this case know the datatype returned by 'getData'. I can't use templates because the user doesn't know how MyClass is implemented. Thank you. Feel free to suggest alternatives.
I think the problem is not in the cast from your array to a void * but in trying to call obj.getArr() when obj is marked const and MyClass::getArr() is not a const member function. If you change your definition of that member function to
const void *getArr() const { return static_cast<const void*>(arr); }
Then this error should resolve itself. You might want to do a const-overload as well:
const void *getArr() const { return static_cast<const void*>(arr); }
void *getArr() { return static_cast< void*>(arr); }