I'm stuck on a compiler error and I can't seem to find a solution online (mainly because google can't handle the syntax). This is the one and only error I'm getting (MVS 2005).
error C2664: 'LinkedList<T>::CreateLinkedList' : cannot convert parameter 2
from 'const MemberInfo *' to 'MemberInfo *const *' memberdata.cpp 59
The error points to this piece of code.
ILinkedList*
MemberData::CreateLinkedList()
{
const MemberInfo* mi = this->get(FIRST);
LinkedList<MemberInfo*>::CreateLinkedList(
MemberInfo::CompareByTime,
mi);
return NULL;
}
The relevant pieces of code in this are:
MemberInfo class
// MemberInfo declaration
class
MemberInfo
{
public:
static int
CompareByTime(
const void* mi1,
const void* mi2);
};
// MemberInfo implementation
int
MemberInfo::CompareByTime(
const void* mi1,
const void* mi2)
{
if ( mi1 == NULL || mi2 == NULL )
return 0;
if ( ((MemberInfo*)mi1)->m_Time > ((MemberInfo*)mi2)->m_Time )
return 1;
if ( ((MemberInfo*)mi2)->m_Time > ((MemberInfo*)mi1)->m_Time )
return -1;
return 0;
}
LinkedList class
typedef int (*ComparatorFcn)(const void*, const void*);
template <class T>
class LinkedList
: public ILinkedList
{
private:
protected:
const T*
m_ptValue;
ComparatorFcn
m_pCompFcn;
LinkedList(
const T* ptVal,
ComparatorFcn func);
public:
static ILinkedList*
CreateLinkedList(
ComparatorFcn func,
const T* ptVal)
{
LinkedList<T>* t = new LinkedList<T>(ptVal, func);
return t;
}
virtual
~LinkedList();
LinkedList<T>*
AddLink(
T* pLink);
virtual bool
Remove();
virtual bool
RemoveLink(
ILinkedList* pLink);
};
I'm quite stuck. I don't understand why the compiler thinks that my argument for the function CreateLinkedList is MemberInfo *const *rather than how I declared it as const MemberInfo* (or const T* actually).
Any help ideas?
Thanks!
Your LinkedList<MemberInfo*> should be LinkedList<MemberInfo>.
Notice that the error message mentions MemberInfo *const * - a pointer to a pointer.
As the type you use to instantiate the template is a MemberInfo *, T will be MemberInfo * and the CreateLinkedList functions expects a T const * aka a MemberInfo * const *.
The type you pass is a MemberInfo const * aka const MemberInfo *.
So, you're asking the compiler to convert from const MemberInfo * to MemberInfo * const *
I see a couple problems:
First, your MemberInfo::CompareByTime() function is written wrong. The way you have written it throws away any type checking the compiler can do. Better would be:
int MemberInfo::CompareByTime(const MemberInfo& mi1, const MemberInfo& mi2)
{
if(mi1.m_Time > mi2.m_Time)
return 1;
if(mi1.m_Time < mi2.m_Time)
return -1;
return 0;
}
Second, pass the comparison function into your linked list as a template parameter:
template <class T, int (*CompFcn)(const T&, const T&)>
class LinkedList: public ILinkedList
Third, there's no reason to hide the constructor and wrap it in a static function that returns the superclass' pointer. C++ will automatically convert an object's pointer to a pointer to its superclass when needed. Also, you should be passing the contained values around by reference (instead of pointer) and store them by value when possible; if you want your container to store pointers, then just set T to a pointer type. So your construction simplifies to:
protected:
T m_ptValue;
public:
LinkedList(const T& ptVal);
Finally, your code for MemberData::CreateLinkedList is broken. It always returns NULL. That is, from the outside it looks like it never creates a linked list. Also, the this-> does nothing. What you should have is:
LinkedList<MemberInfo*, MemberInfo::CompareByTime>* MemberData::CreateLinkedList()
{
return new LinkedList<MemberInfo*, MemberInfo::CompareByTime>(get(FIRST));
}
Though it's probably good practice to define typedef LinkedList<MemberInfo*, MemberInfo::CompareByTime> LinkedListType; in MemberData, which lets us write:
MemberData::LinkedListType* MemberData::CreateLinkedList()
{
return new LinkedListType(get(FIRST));
}
Note that the return value will be typecast to ILinkedList* automatically where needed.
First of all, there is no difference between const T and T const. It is allowed to add the const keyword after the type. In many situations that is the only way to exactly specify what part of the type const is.
You are using const T* (or T const *). where T is MemberInfo*:
LinkedList<MemberInfo*>::CreateLinkedList(
So the full type is MemberInfo * const *. Note that this is not the same as const MemberInfo * * (or MemberInfo const * *).
Related
I have a function like this:
void column(const std::string &value) { ... }
void column(float value) { ... }
template <class... TColumns> void row(const TColumns &...columns) {
ImGui::TableNextRow();
(column(columns), ...);
}
I am using clang-tidy static analyzer to make sure that my code is always compliant with cpp core guidelines. I am using this function in the following way:
// (const char[5], float)
row("Hello", 20.5f);
My understanding is that, std:string accepts const char * but the first argument of the function call above gets inferred to const char[5]. This causes array decay and I get clang-tidy error that:
do not implicitly decay an array into a pointer; consider using gsl::array_view or an explicit cast instead
Is it possible to somehow enforce that string argument that is passed is always const char *, not const char[5] or const char[6] etc?
Since you anyways convert a c-string to a string each time you reach this line, it's suggested to have a static string. That is expected to solve the warning as well.
#include <iostream>
void column(const std::string &value) { }
void column(float value) { }
template <class... TColumns> void row(const TColumns &...columns) {
// ...
(column(columns), ...);
}
int main() {
static auto hello = std::string{"Hello"};
row(hello, 20.5f);
}
However, the best solution is likely to simply turn off the warning - either globally, or as Drew wrote, via // NOLINT.
I have 2 classes: Child derives from Parent:
#include <stdint.h>
#include <iostream>
using namespace std;
class Parent
{
public:
int parentMember;
};
class Child : public Parent
{
};
Now, I have a class template for custom implementation of a dynamic array (unnecessary parts skipped)
template <typename T>
class DArray
{
private:
T* m_array;
int32_t m_length;
public:
// Default constructor
DArray() : m_array{ nullptr }, m_length{ 0 } {
};
// Search returns index of the first found item or -1 if not found, comparison is done
// using function pointer, which should return boolean
int32_t Search(const T& data, bool(*comparisonFunction)(T, T)) {
for (int32_t i = 0; i < m_length; i++) {
if (comparisonFunction(m_array[i], data))
return i;
}
return -1;
}
};
I have a comparison function that will be used to find out if my dynamic array already contains an element with the same value of parentMember
bool comparisonFunction(Parent* n1, Parent* n2) {
return (n1->parentMember == n2->parentMember);
}
Lastly, I have my dynamic array, which should hold pointers to Child objects.
int main()
{
DArray<Child*> dArray;
Child *c;
dArray.Search(c, comparisonFunction);
return 0;
}
This code returns error on this line:
dArray.Search(c, comparisonFunction);
The error is:
argument of type "bool (*)(Parent *n1, Parent *n2)" is incompatible with
parameter of type "bool (*)(Child *, Child *)"
My question is: Why doesn't the compiler implicitly convert Child* to Parent* as it does when I pass Child* as an argument to a function which takes Parent* as a parameter?
Is there any way how to solve this problem without implementing a new comparison function for every single child class?
There are no implicit conversions between pointer to function types.
I would change your Search function to a template function which can take any functor type (including lambdas, std::function, etc.).
template <typename F>
int32_t Search(const T& data, const F& comparisonFunction) {
for (int32_t i = 0; i < m_length; i++) {
if (comparisonFunction(m_array[i], data))
return i;
}
return -1;
}
The implicit conversion from Child * to Parent * is not necessarily a no-op. It can involve pointer arithmetic and even conditionals (for checking null). So while it's possible to call a function expecting a Parent * with an argument of type Child *, it's only possible because the compiler will insert any necessary conversion code in the point of the call.
This means that while you can convert a Child * into a Parent *, you cannot directly treat a Child * as a Parent *. However, you algorithm uses a pointer to a function of type bool(Child*, Child*). So it will pass two Child * objects into that function. At the site of the call through the function pointer, the compiler has no way of knowing that the pointer actually points to a bool(Parent *, Parent*) and that it should therefore insert conversion code from Child * to Parent * for each of the arguments.
No such code can be inserted at the site passing the pointer either. The compiler would effectively have to synthesise a wrapper of type bool(Child *, Child *), put the conversion code into it, and pass a pointer to that wrapper into Search. That would be a bit too expensive for a single implicit conversion.
The correct solution to your problem has already been given by other answers: take inspiration from the standard <algorithm> header and accept an arbitrary functor instead of a function pointer:
template <class F>
int32_t Search(const T& data, F comparisonFunction) {
for (int32_t i = 0; i < m_length; i++) {
if (comparisonFunction(m_array[i], data))
return i;
}
return -1;
}
The compiler won't do this.
Generally it is best to submit functors as template parameters that way it will work with any item that could compile in that place. std::function and capturing lambda's for example would work with template arguments but not explicit function pointer declaration.
template <typename T>
class DArray
{
private:
T* m_array;
int32_t m_length;
public:
// Default constructor
DArray() : m_array{ nullptr }, m_length{ 0 } {
};
// Search returns index of the first found item or -1 if not found, comparison is done
// using function pointer, which should return boolean
template<typename COMPARE>
int32_t Search(const T& data,COMPARE& compareFunction) {
for (int32_t i = 0; i < m_length; i++) {
if (compareFunction(m_array[i], data))
return i;
}
return -1;
}
};
If I derive from CBaseInterface (see code below) with template Argument T=int*, the compiler fails wirh error C2555. This happens with all pointer types used for T. If I use a typedef instead, the same code works fine.
// If _FALIS is defined, the compiler fails, else it succeeds
// (MS Visual Studio 2013 Update 2, 32 and 64 Bit native C++, Debug build).
#define _FALIS
#ifdef _FALIS
#define PINT int*
#else
typedef int* PINT;
#endif
template <class T>
class CBaseInterface
{
public:
virtual ~CBaseInterface() {}
virtual const T Calculate() const = 0;
};
class CCalculator : public CBaseInterface<PINT>
{
public:
CCalculator() {}
virtual ~CCalculator() {}
// error C2555: 'CCalculator::Calculate':
// overriding virtual function return type differs and is not 'covariant'
// from 'CBaseInterface<int *>::Calculate'
virtual inline const PINT Calculate() const final
{
return (PINT)&m_Item;
}
protected:
int m_Item = 0;
};
Where is the problem with the pointer types? I am confused and I didn't find anything in Microsoft's docs that fits at this Situation.
Hope you can help me.
The difference is to do with the meaning of const PINT in the derived class.
If PINT is a typedef for int *, then const PINT is an int * const (constant pointer to mutable int) - which is fine, that's what the base class function is defined to return. If you use your macro then you have literally const int * (mutable pointer to constant int), which is a completely different type. The typedef is substituted logically into the type system, the macro is substituted blindly as tokens.
One way to rescue this would be to write PINT const or const (PINT) (so the binding of the const is explicit).
And you really shouldn't use macros.
I am trying to pass a STL container in a class to another class
For ex.
typedef std::map<std::string, int*> Container_t;
class A
{
public:
const Container_t * get_container() const;
private:
Container_t container;
};
const Container_t * A::get_container() const
{
return &container;
}
And when I try to get this in another class, I get compilation error
saying
error: argument of type ‘Container_t* (A::)()const’ does not match ‘Container_t*’
void foo(A * a)
{
const Container_t * container = a->get_container();
}
It will be best if I can get const reference instead of pointer. but I don't want to copy the return value of function in A. So it has to be either pointer or reference. Thank you
You need to change your function signature to:
const Container_t * get_container() const;
The reason is that the last const there at the end says "calling this function and using what it returns will not change this object." However, returning a (non-const) pointer to the member variable gives the caller freedom to change that variable, so you have to return a const Container_t * to ensure that the caller doesn't modify the member variable (and thereby modify the object).
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); }