开发者

QT C++ forward-declaration problem?

I am trying to use QTPropertyBrowser to edit properties in my QObjects. From QT Solutions "QtPropertyBrowser" example I use following files in my project.

http://qt.gitorious.org/qt-solutions/qt-solutions/blobs/master/qtpropertybrowser/examples/object_controller/objectcontroller.cpp

http://qt.gitorious.org/qt-solutions/qt-solutions/blobs/master/qtpropertybrowser/examples/object_controller/objectcontroller.h

I configure my CMakeFile as follows :

#include_directories("/usr/include")
SET(QTVIEW_SRCS 
  src/main.cpp  
  src/TestWidget.cpp
  src/plugin/IPlugin.cpp
  src/objectcontroller.cpp
)

SET(QTVIEW_MOH_HDRS
 src/TestWidget.h
 src/plugin/IPlugin.h
 src/objectcontroller.h

)

When I compile the files as they are, compiler giving error as follows -

C:\svn\osaka3d\trunk\osaka3d\QTView\src\moc_objectcontroller.cxx: In member function 'virtual int ObjectController::qt_metacall(QMetaObject::Call, int, void**)' : C:\svn\osaka3d\trunk\osaka3d\QTView\src\moc_objectcontroller.cxx:73: error: invalid use of incomplete type 'struct ObjectControllerPrivate' C:\svn\osaka3d\trunk\osaka3d\QTView\src/objectcontroller.h:45: error: forward declaration of 'struct ObjectControllerPrivate' C:\svn\osaka3d\trunk\osaka3d\QTView\src\moc_object开发者_运维技巧controller.cxx:73: error: expected type-specifier before 'QtProperty' C:\svn\osaka3d\trunk\osaka3d\QTView\src\moc_objectcontroller.cxx:73: error: expected '>' before 'QtProperty' C:\svn\osaka3d\trunk\osaka3d\QTView\src\moc_objectcontroller.cxx:73: error: expected '(' before 'QtProperty' C:\svn\osaka3d\trunk\osaka3d\QTView\src\moc_objectcontroller.cxx:73: error: 'QtProperty' was not declared in this scope C:\svn\osaka3d\trunk\osaka3d\QTView\src\moc_objectcontroller.cxx:73: error: expected primary-expression before ')' token mingw32-make2: * [CMakeFiles/qtview.dir/src/moc_objectcontroller.cxx.obj] Error 1 mingw32-make1: [CMakeFiles/qtview.dir/all] Error 2 mingw32-make: ** [all] Error 2

But when I comment out the line :

Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QVariant &))

in "objectcontroller.h"

and comment out the line :

#include "moc_objectcontroller.cxx"

and the end of file "objectcontroller.cpp" , it compiles well But i cannot use SIGNALS/SLOTs to reflect editing of QObject parameters.

Any tips?


I ran into the same problem (I am new to qt, but this worked for me). For other people searching a solution I found this:

What is happening

The issue is that due to Q_PRIVATE_SLOT macro the generated moc_XXX.cxx needs the full declaration of the XXXPrivate class to call the private slot function. As the public header only forward declares it, the generated cxx can not be compiled on its own. The QtPropertyBrowser guys circumvented this problem by including the generated moc_XXX.cpp (mind the 'pp', cmake generates 'xx')) in their source file (ugly, but works). I also do not know any other way to tell the moc to include (the in this case even not present) private XXX_p.hpp. So let's stick to that way.

What I did next was to remove the generated moc_XXX.cxx files from the executable, but this resulted in the moc never being called. This happened even though I used QT4_WRAP_CPP. So after further searching I found...

One addendum to this special case: the QtProperty declaration is missing. Either add the following forward declaration or the appropriate include file:

#if QT_VERSION >= 0x040400
QT_BEGIN_NAMESPACE
#endif

class QtProperty;

#if QT_VERSION >= 0x040400
QT_END_NAMESPACE
#endif

Solution

Full credit goes to fullmetalcoder who presented this cmake function:

function(qt4_wrap_hdrs _moc_srcs)
  qt4_get_moc_flags(_moc_incs)
  set(_mocs)
  foreach(_current_file ${ARGN})
    get_filename_component(_abs_file ${_current_file} ABSOLUTE)
    if(EXISTS ${_abs_file})
      file(READ ${_abs_file} _contents)
      get_filename_component(_basename ${_abs_file} NAME_WE)
      string(REGEX MATCH "Q_OBJECT" _match "${_contents}")
      if(_match)
        set(_moc "${CMAKE_CURRENT_BINARY_DIR}/moc_${_basename}.cpp")
        qt4_create_moc_command(${_abs_file} ${_moc} "${_moc_incs}" "")
        macro_add_file_dependencies(${_abs_file} ${_moc})
        list(APPEND _mocs ${_moc})
      endif(_match)
    endif(EXISTS ${_abs_file})
  endforeach (_current_file)
  set(${_moc_srcs} ${_mocs} PARENT_SCOPE)
endfunction(qt4_wrap_hdrs)

(from http://www.qtcentre.org/threads/37428-using-QT-unit-testing-with-CMake)

You can use this function as a drop-in replacement for QT4_WRAP_CPP. You now only need to add the following line into your CMakeLists.txt so that the compiler finds the generated moc_XXX.cpp files (the new function created a 'pp' file...):

include_directories(${CMAKE_BINARY_DIR})

This function calls the moc all the time and behaves more like as in the qmake case. Except of course that you can easily do out of source builds.

But there is one caveat: all moc_XXX.cpp files are generated in the CMAKE_BINARY_DIR. So if you have two files include1/foo.hpp and include2/foo.hpp one will be overwritten!


Have you read the following article about using Qt and CMake together?

http://developer.qt.nokia.com/quarterly/view/using_cmake_to_build_qt_projects

Maybe you're forgetting something, like calling QT4_WRAP_CPP on your CMakeLists.txt.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜