I’m trying to use a typedef from a subclass in my project, I’ve isolated my problem in the example below.
Does anyone know where I’m going wrong?
template<typename Subclass>
class A {
public:
//Why doesn't it like this?
void action(typename Subclass::mytype var) {
(static_cast<Subclass*>(this))->do_action(var);
}
};
class B : public A<B> {
public:
typedef int mytype;
B() {}
void do_action(mytype var) {
// Do stuff
}
};
int main(int argc, char** argv) {
B myInstance;
return 0;
}
This is the output I get:
sean@SEAN-PC:~/Documents/LucadeStudios/experiments$ g++ -o test test.cpp
test.cpp: In instantiation of ‘A<B>’:
test.cpp:10: instantiated from here
test.cpp:5: error: invalid use of incomplete type ‘class B’
test.cpp:10: error: forward declaration of ‘class B’
asked Mar 16, 2009 at 21:07
seanhodgesseanhodges
17.3k15 gold badges70 silver badges93 bronze badges
The reason is that when instantiating a class template, all its declarations (not the definitions) of its member functions are instantiated too. The class template is instantiated precisely when the full definition of a specialization is required. That is the case when it is used as a base class for example, as in your case.
So what happens is that A<B>
is instantiated at
class B : public A<B>
at which point B
is not a complete type yet (it is after the closing brace of the class definition). However, A<B>::action
‘s declaration requires B
to be complete, because it is crawling in the scope of it:
Subclass::mytype
What you need to do is delaying the instantiation to some point at which B
is complete. One way of doing this is to modify the declaration of action
to make it a member template.
template<typename T>
void action(T var) {
(static_cast<Subclass*>(this))->do_action(var);
}
It is still type-safe because if var
is not of the right type, passing var
to do_action
will fail.
answered Mar 16, 2009 at 21:36
1
You can get around this by using a traits class:
It requires you set up a specialsed traits class for each actuall class you use.
template<typename SubClass>
class SubClass_traits
{};
template<typename Subclass>
class A {
public:
void action(typename SubClass_traits<Subclass>::mytype var)
{
(static_cast<Subclass*>(this))->do_action(var);
}
};
// Definitions for B
class B; // Forward declare
template<> // Define traits for B. So other classes can use it.
class SubClass_traits<B>
{
public:
typedef int mytype;
};
// Define B
class B : public A<B>
{
// Define mytype in terms of the traits type.
typedef SubClass_traits<B>::mytype mytype;
public:
B() {}
void do_action(mytype var) {
// Do stuff
}
};
int main(int argc, char** argv)
{
B myInstance;
return 0;
}
answered Mar 16, 2009 at 22:07
Martin YorkMartin York
253k84 gold badges332 silver badges555 bronze badges
2
You derive B
from A<B>
, so the first thing the compiler does, once it sees the definition of class B
is to try to instantiate A<B>
. To do this it needs to known B::mytype
for the parameter of action
. But since the compiler is just in the process of figuring out the actual definition of B
, it doesn’t know this type yet and you get an error.
One way around this is would be to declare the parameter type as another template parameter, instead of inside the derived class:
template<typename Subclass, typename Param>
class A {
public:
void action(Param var) {
(static_cast<Subclass*>(this))->do_action(var);
}
};
class B : public A<B, int> { ... };
answered Mar 16, 2009 at 21:29
sthsth
218k53 gold badges277 silver badges364 bronze badges
Not exactly what you were asking, but you can make action a template member function:
template<typename Subclass>
class A {
public:
//Why doesn't it like this?
template<class V> void action(V var) {
(static_cast<Subclass*>(this))->do_action();
}
};
class B : public A<B> {
public:
typedef int mytype;
B() {}
void do_action(mytype var) {
// Do stuff
}
};
int main(int argc, char** argv) {
B myInstance;
return 0;
}
answered Mar 16, 2009 at 21:45
John DiblingJohn Dibling
98.8k29 gold badges183 silver badges321 bronze badges
You need to use a pointer or a reference as the proper type is not known at this time the compiler can not instantiate it.
Instead try:
void action(const typename Subclass::mytype &var) {
(static_cast<Subclass*>(this))->do_action();
}
answered Mar 16, 2009 at 21:17
1
Problem:
You are compiling a C/C++ program using GCC. You get an error message similar to this:
error: invalid use of incomplete type ‘class SomeType’
Solution:
There are multiple possible issues, but in general this error means that GCC can’t find the full declaration of the given class or struct.
The most common issue is that you are missing an #include
clause. Find out in which header file the declaration resides, i.e. if the error message mentions class Map
, look for something like
class Map { // ... };
Usually the classes reside in header files that are similar to their name, e.g. MyClass
might reside in a header file that is called MyClass.h
, MyClass.hpp
or MyClass.hxx
, so be sure to look for those files first. Note that you might also be looking for a type from a library. Often the best approach is to google C++ <insert the missing type here>
to find out where it might be located.
Another possible reason is that you have your #include
clause after the line where the error occurs. If this is the case, ensure that all required types are included before they are used.
For other reasons, see StackOverflow, e.g. this post
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
#include "dialogadddevice.h" #include "ui_dialogadddevice.h" DialogAddDevice::DialogAddDevice(int row, QWidget *parent) : QDialog(parent), ui(new Ui::DialogAddDevice) { ui->setupUi(this); /* Метода для инициализации модели, * из которой будут транслироваться данные * */ setupModel(); /* Если строка не задана, то есть равна -1, * тогда диалог работает по принципу создания новой записи. * А именно, в модель вставляется новая строка и работа ведётся с ней. * */ if(row == -1){ model->insertRow(model->rowCount(QModelIndex())); mapper->toLast(); /* В противном случае диалог настраивается на заданную запись * */ } else { mapper->setCurrentModelIndex(model->index(row,0)); } createUI(); } DialogAddDevice::~DialogAddDevice() { delete ui; } /* Метод настройки модели данных и mapper * */ void DialogAddDevice::setupModel() { /* Инициализируем модель и делаем выборку из неё * */ model = new QSqlTableModel(this); model->setTable(DEVICE); model->setEditStrategy(QSqlTableModel::OnManualSubmit); model->select(); /* Инициализируем mapper и привязываем * поля данных к объектам LineEdit * */ mapper = new QDataWidgetMapper(); mapper->setModel(model); mapper->addMapping(ui->HostnameLineEdit, 1); mapper->addMapping(ui->IPAddressLineEdit, 2); mapper->addMapping(ui->MACLineEdit, 3); /* Ручное подтверждение изменения данных * через mapper * */ mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit); /* Подключаем коннекты от кнопок пролистывания * к прилистыванию модели данных в mapper * */ connect(ui->previousButton, SIGNAL(clicked()), mapper, SLOT(toPrevious())); connect(ui->nextButton, SIGNAL(clicked()), mapper, SLOT(toNext())); /* При изменении индекса в mapper изменяем состояние кнопок * */ connect(mapper, SIGNAL(currentIndexChanged(int)), this, SLOT(updateButtons(int))); } /* Метод для установки валидатора на поле ввода IP и MAC адресов * */ void DialogAddDevice::createUI() { QString ipRange = "(?:[0-1]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])"; QRegExp ipRegex ("^" + ipRange + "\." + ipRange + "\." + ipRange + "\." + ipRange + "$"); QRegExpValidator *ipValidator = new QRegExpValidator(ipRegex, this); ui->IPAddressLineEdit->setValidator(ipValidator); QString macRange = "(?:[0-9A-Fa-f][0-9A-Fa-f])"; QRegExp macRegex ("^" + macRange + "\:" + macRange + "\:" + macRange + "\:" + macRange + "\:" + macRange + "\:" + macRange + "$"); QRegExpValidator *macValidator = new QRegExpValidator(macRegex, this); ui->MACLineEdit->setValidator(macValidator); } void DialogAddDevice::on_buttonBox_accepted() { /* SQL-запрос для проверки существования записи * с такими же учетными данными. * Если запись не существует или находится лишь индекс * редактируемой в данный момент записи, * то диалог позволяет вставку записи в таблицу данных * */ QSqlQuery query; QString str = QString("SELECT EXISTS (SELECT " DEVICE_HOSTNAME " FROM " DEVICE " WHERE ( " DEVICE_HOSTNAME " = '%1' " " OR " DEVICE_IP " = '%2' )" " AND id NOT LIKE '%3' )") .arg(ui->HostnameLineEdit->text(), ui->IPAddressLineEdit->text(), model->data(model->index(mapper->currentIndex(),0), Qt::DisplayRole).toString()); query.prepare(str); query.exec(); query.next(); /* Если запись существует, то диалог вызывает * предупредительное сообщение * */ if(query.value(0) != 0){ QMessageBox::information(this, trUtf8("Ошибка хоста"), trUtf8("Хост с таким именем или IP-адресом уже существует")); /* В противном случае производится вставка новых данных в таблицу * и диалог завершается с передачей сигнала для обновления * таблицы в главном окне * */ } else { mapper->submit(); model->submitAll(); emit signalReady(); this->close(); } } void DialogAddDevice::accept() { } /* Метод изменения состояния активности кнопок пролистывания * */ void DialogAddDevice::updateButtons(int row) { /* В том случае, если мы достигаем одного из крайних (самый первый или * самый последний) из индексов в таблице данных, * то мы изменяем состояние соответствующей кнопки на * состояние неактивна * */ ui->previousButton->setEnabled(row > 0); ui->nextButton->setEnabled(row < model->rowCount() - 1); } |
I have the following errors trying to use a TFT library function inside my library. My library uses the pointer to an instance of the TFT library in the constructor, as well described there:
Basic C++ programming, how to pass constructor argument into class?
The errors are:
error: invalid use of incomplete type 'class TFT'
_TFTscreen->background(0, 0, 0);
error: forward declaration of 'class TFT'
class TFT;
MESmenu.h:
#ifndef _MESMENU_H_
#define _MESMENU_H_
#include <SPI.h>
#include <SD.h>
class TFT;
class MESmenu{
public:
MESmenu(TFT* pTFT) : _TFTscreen(pTFT) {};
void start();
void execute();
private:
TFT* _TFTscreen;
};
#endif
MESmenu.cpp:
#include "Arduino.h"
#include "MESmenu.h"
void MESmenu::start(){
_TFTscreen->background(0, 0, 0);
_TFTscreen->text("starting menu...", 0, 0);
//...
}
void MESmenu::execute(){
//some code...
}
The Arduino sketch is:
#include <SPI.h>
#include <SD.h>
#include <TFT.h> // Arduino LCD library
#include <MESmenu.h> // my library
// --------- TFT LCD ---------
// pin definition for the due
#define sd_cs 7
#define lcd_cs 10
#define dc 9
#define rst 8
TFT TFTscreen = TFT(lcd_cs, dc, rst);
// MES menu class
MESmenu *mainMenu = new MESmenu(&TFTscreen);
void setup() {
// initialize TFT
TFTscreen.begin();
TFTscreen.background(0, 0, 0);
// set the stroke color to white
TFTscreen.stroke(255,255,255);
TFTscreen.fill(255,255,255);
TFTscreen.setTextSize(2);
TFTscreen.text("TEST", 0, 0);
// Start menu
mainMenu->start();
}
void loop () {
mainMenu->execute();
}
The problem is related to the function:
_TFTscreen->background(0, 0, 0);
inside the MESmenu::start() in the .cpp file.
UPDATE:
As suggested by frarugi87 I’ve updated the question with the details of .h and .cpp files.
Those file are in the ArduinolibrariesMESmenu folder.
I try to change
class TFT;
with
#include <TFT.h>
and removed the #include from the main arduino sketch.
This leads to the following errors:
librariesMESmenuMESmenu.cpp.o: In function `Adafruit_GFX::image(PImage&, unsigned int, unsigned int)':
D:Softwarearduino-1.6.7librariesTFTsrc/utility/Adafruit_GFX.h:231: multiple definition of `Adafruit_GFX::image(PImage&, unsigned int, unsigned int)'
sketchtest_MESmenu_lib.ino.cpp.o:D:Softwarearduino-1.6.7librariesTFTsrc/utility/Adafruit_GFX.h:231: first defined here
librariesMESmenuMESmenu.cpp.o: In function `Adafruit_GFX::image(PImage&, unsigned int, unsigned int)':
D:Softwarearduino-1.6.7librariesTFTsrc/utility/Adafruit_GFX.h:231: multiple definition of `PImage::read16(SDLib::File)'
sketchtest_MESmenu_lib.ino.cpp.o:D:Softwarearduino-1.6.7librariesTFTsrc/utility/PImage.h:17: first defined here
librariesMESmenuMESmenu.cpp.o: In function `Adafruit_GFX::image(PImage&, unsigned int, unsigned int)':
D:Softwarearduino-1.6.7librariesTFTsrc/utility/Adafruit_GFX.h:231: multiple definition of `PImage::read32(SDLib::File)'
sketchtest_MESmenu_lib.ino.cpp.o:D:Softwarearduino-1.6.7librariesTFTsrc/utility/PImage.h:17: first defined here
librariesMESmenuMESmenu.cpp.o: In function `Adafruit_GFX::image(PImage&, unsigned int, unsigned int)':
D:Softwarearduino-1.6.7librariesTFTsrc/utility/Adafruit_GFX.h:231: multiple definition of `PImage::loadImage(char const*)'
sketchtest_MESmenu_lib.ino.cpp.o:D:Softwarearduino-1.6.7librariesTFTsrc/utility/PImage.h:17: first defined here
Forum Updated on Feb 6th
This topic has been deleted. Only users with topic management privileges can see it.
-
C:UsersLorence30Desktoptestmainwindow.h:32: error: invalid use of incomplete type ‘class Ui::MainWindow’ ui->grassyTile
^why i keep getting this error?
I have my Q_OBJECT macro inside the MainWindow class.
*[link text](link url) class MainWindow : public QMainWindow
{
Q_OBJECTpublic:
explic[it MainWindow(QWidget *parent = 0);
~MainWindow();](link url)private slots:
void changeTile();
void pushTile();private:
Ui::MainWindow *ui;
int counter;std::array<Tile,1> tile_list { ui->grassyTile // heres where error coming from };
};
-
@Lorence said:
grassyTile
What type is that ?
«use of incomplete type» often means a include file is missing
or you forwarded a class
like
class SomeClass;And try to use it in a context where it needs to be fully defined.
Like adding to some template lists.Not sure what you tried to define here ?
std::array<Tile,1> tile_list <—- ; missing here?
{
ui->grassyTile // heres where error coming from
}; -
grassyTile is of type Tile that is inheriting QLabel
Not sure what you tried to define here ?
i dont know how to list intialize an array on constructor so i decided to do it in side a class definition -
@mrjj said:
and «tile.h» is included ?
in mainwindow.hdo you mean like ?
std::array<std::string, 2> strings = {{ «a», «b» }}; -
and «tile.h» is included ?
yes i got all i need included.
do you mean like ?
std::array<std::string, 2> strings = {{ «a», «b» }};yes, in the mainwindow.cpp i can freely use ui->grassyTile; without error.
-
@Lorence
Ok so it must be the tile_list statement.Would it like
std::array<Tile,1> tile_list {{ui->grassyTile }}; -
Would it like
std::array<Tile,1> tile_list {{ui->grassyTile }};thanks for the help but i still get the same error
-
@Lorence
Ok, and you are 100% it knows the tile type here?
you can declare one over the tile_list and it will like it ?
Tile *Test;One thing I wonder, you say
std::array<Tile> and not std::array<Tile *) or & so it must make a copy of
it (the tile). Is that the effect you want? -
@Lorence
Hmm it seems its «ui» it do not like.
Let me test. -
@mrjj
ahh, Ui::MainWindow is defined in
#include «ui_main_window.h»
which is included in the CPP file so the type is not fully defined so you cannot say
ui->Somename
as Ui::MainWindow is not defined yet.moving
#include «ui_main_window.h»
to the minwin.h file allows it but not sure if it will confuse Qt Creator.Also it will complain about not being able to convert Tile to Tile * as list is not pointers and ui->grassyTile will be.
-
ahh, Ui::MainWindow is defined in
#include «ui_main_window.h»didnt think of that, thanks! but new error comes
-
@Lorence
Yeah, it tries to construct a new Tile to go into the list.
Can I ask if you want a list of pointers to tiles you have on screen or
a list with new Tiles that has nothing to do with those on screen? -
sorry for the late reply.
i just want a list of tiles to choose from.
but QT disabled the copying of QLabel,
so i really need to have a pointer of tiles? -
@Lorence
heh 9 mins is not considered latethen the list must be pointer type or it will be new ones and not the ones on screen.
so
std::array<Tile> should be std::array<Tile *> or std::array<Tile &>
so its the ones on screen and not new ones
Yes you must at least use & as it must «point» to the real one. -
then the list must be pointer type
yea, i edited my last replyit will be new ones and not the ones on screen.
it is the ones on the screen, there will be a list of tiles on the screen and the user will choose what tiles they want to render
*so
std::array<Tile> should be std::array<Tile > or std::array<Tile &>
so its the ones on screen and not new ones
Yes you must at least use & as it must «point» to the real one.thanks!!!!!!!!
all my problem is fixed
I have not coded for weeks and C++ is already kicking me damit
-
@mrjj said:
ok. Superand tile_list is the ones to choose from ?
Dont worry. I programmed c++ for 20 years and it still kicks me
-
and tile_list is the ones to choose from ?
yes, it is a list of Tile which is inheriting QLabel
Dont worry. I programmed c++ for 20 years and it still kicks me
woaaaaa, me is about a year, and started this QT last week, i choose this for my tile engine’s interface from SFML, i still have more ways to go !^_^
-
@Lorence said:
welcome on board to Qt. its a nice frame work.Oh so its some sort of game editor your are making ?
-
welcome on board to Qt. its a nice frame work.
Yes my first choice is wxwidget and windows form application, but signals and slots mechanism of qt makes me decide to choose qt
Oh so its some sort of game editor your are making ?
yes exatcly, like the rpg maker vx ace of steam
- Forum
- Beginners
- Invalid use of incomplete type?
Invalid use of incomplete type?
Here is a simplified version of the problem i’m facing in my code:
|
|
When I define the test() method outside of the class, the compiler gives me a «invalid use of incomplete type» error, but it works fine when the function is defined inline. I am defining the entire class and the definitions in the same file, so why is it giving me this error?
Last edited on
you can’t just say complex a. you have to give it a type.
complex <double> a; when you make a variable of the type, eg in main there…
Last edited on
jonnin wrote: |
---|
you can’t just say complex a. you have to give it a type. |
That’s not correct. Omitting the template brackets when the type has a default is perfectly valid in C++17.
My problem is that I am getting an invalid use of incomplete type when I define test() outside of the class. If it were defined inline it works perfectly. I suspect it has something to do with the unnamed typename parameter I am using for SFINAE, but I am not sure why. Can you help me with this?
Last edited on
|
|
@Ganado
Huh, strange. I assumed if a type parameter didn’t have a name it didn’t need to be named in the member function definition outside of the class. This seems quite strange that you can leave it unnamed inside the class definition, but you have to give it a name outside. This means that Complex<T> is valid in the class but not outside of it. Weird. Anyway, thank you. Fixed.
Last edited on
To be honest I’m not sure of the formal rules here, but my gut feeling would say that you can’t ignore one of the template parameters in the definition of the function template.
By the way, it seems you’re trying to restrict the use of the Complex type to only be float, double, or long double, right?
A static_assert might be simpler here. And I imagine C++20 Concepts would help here and supersede static_assert, although I have not used Concepts yet in practice.
|
|
Or even better:
|
|
Last edited on
Ganado wrote: |
---|
To be honest I’m not sure of the formal rules here, but my gut feeling would say that you can’t ignore one of the template parameters in the definition of the function template. |
It seems that the rules are even weirder if you have an object of type Complex passed as a parameter or a return value. Here is what the out-of-class definition would look like:
|
|
So in the case of a parameter or a return value, you have to use Complex<T> as normal. Complex<T,U> is only for the disambiguation of the member function. If you try to use Complex<T,U> as a return value or a parameter the compiler complains. Weird!
Topic archived. No new replies allowed.
|
Автор | Тема: invalid use of incomplete type (решено) (Прочитано 24742 раз) |
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
InvalidConversion
is a dummy class: it’s declared but not defined.
ArduinoJson uses this class to trigger a compilation error with a distinctive pattern.
Thanks to this class, when you try to perform an invalid conversion, you get an error like this one:
In file included from .../ArduinoJson/Array/ArrayIterator.hpp:8:0,
from .../ArduinoJson/Array/ArrayRef.hpp:8,
from .../ArduinoJson.hpp:17,
from .../ArduinoJson.h:9,
from MyProgram.ino:9:
.../ArduinoJson/Variant/JsonVariant.hpp: In instantiation of 'typename ArduinoJson6180_91::enable_if<((! ArduinoJson6180_91::is_same<T, char*>::value) && (! ArduinoJson6180_91::is_same<T, char>::value)), T>::type ArduinoJson6180_91::JsonVariantConst::as() const [with T = ArduinoJson6180_91::ObjectRef; typename ArduinoJson6180_91::enable_if<((! ArduinoJson6180_91::is_same<T, char*>::value) && (! ArduinoJson6180_91::is_same<T, char>::value)), T>::type = ArduinoJson6180_91::ObjectRef]':
MyProgram.ino:37:44: required from here
.../ArduinoJson/Variant/JsonVariant.hpp:251:34: error: invalid use of incomplete type 'class ArduinoJson6180_91::InvalidConversion<ArduinoJson6180_91::JsonVariantConst, ArduinoJson6180_91::ObjectRef>'
return Converter<T>::fromJson(*this);
~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
In file included from .../ArduinoJson/Variant/JsonVariant.hpp:14:0,
from .../ArduinoJson/Array/ArrayIterator.hpp:8,
from .../ArduinoJson/Array/ArrayRef.hpp:8,
from .../ArduinoJson.hpp:17,
from .../ArduinoJson.h:9,
from MyProgram.ino:9:
.../ArduinoJson/Variant/Converter.hpp:14:7: note: declaration of 'class ArduinoJson6180_91::InvalidConversion<ArduinoJson6180_91::JsonVariantConst, ArduinoJson6180_91::ObjectRef>'
class InvalidConversion; // Error here? See https://arduinojson.org/v6/invalid-conversion/
^~~~~~~~~~~~~~~~~
As you can see, InvalidConversion
is a template class that takes two arguments. The first is the original type, and the second is the type it’s converted to. Unfortunately, the error shows the internal names instead of the public names.
For example, after removing the namespaces in the error above, it says:
invalid use of incomplete type 'class InvalidConversion<JsonVariantConst, ObjectRef>'
The internal name JsonVariantConst
corresponds to JsonVariantConst
, and ObjectRef
corresponds to JsonObject
. Indeed, converting from JsonVariantConst
to JsonObject
is invalid because it would convert a read-only reference to a read-write reference.
To fix this issue, you must convert the read-only reference to a read-only reference. In our example, it means we must replace JsonObject
with JsonObjectConst
.
So, somewhere in the program, there is a statement like variant.as<JsonObject>()
or JsonObject obj = variant
that must be changed into variant.as<JsonObjectConst>()
or JsonObjectConst obj = variant
.