错误:模板类型不完整

时间:2016-03-22 22:05:59

标签: c++ oop templates incomplete-type

我遇到使用不完全模板类型的问题。我已经搜索了很长一段时间才找到解决方案,但我找到的每个答案都倾向于按照#34;包括标题," "转发声明,"或者"你不能用STL做到这一点。"我有一种感觉,我正在寻找错误的东西,或者前十几页谷歌被淹没

虽然我肯定在寻找解决方案,但我非常感谢您的解释,或者可能是指向良好指南的链接。对于模仿严重的OOP我很新,并且很想知道错误是什么,错误是什么以及原因。

因此,我将尝试尽可能包含AS MUCH代码,而不会向您提供多个500行文件。省略号是我删除与此问题无关的代码(或者我删除了其他方向迭代和更大的模板的地方)。此外,SpatialOps是我们用于空间操作的库。如果我删除我在这里发布的代码,一切都链接正常,一切都通过CMake编译好。 从错误消息开始:

/scratch/local/prism_large/dac/debugging/LBMS2/src/operators/Operators.cpp: In function ‘void LBMS::build_operators(const BundlePtr&)’:
/scratch/local/prism_large/dac/debugging/LBMS2/src/operators/Operators.cpp:154:96: error: invalid use of incomplete type ‘SpatialOps::X2PosX {aka struct SpatialOps::OneSidedOpTypeBuilder<SpatialOps::Gradient, SpatialOps::OneSidedStencil2<SpatialOps::IndexTriplet<1, 0, 0> >, SpatialOps::SpatialField<LBMS::XVol, double> >}’
   opDB.register_new_operator<SpatialOps::X2PosX>( new SpatialOps::X2PosX( coefHalfDx2Plus  ) );
                                                                                            ^
In file included from /scratch/local/prism_large/dac/debugging/LBMS2/src/operators/Operators.h:6:0,
             from /scratch/local/prism_large/dac/debugging/LBMS2/src/operators/Operators.cpp:1:
/scratch/local/prism_large/dac/debugging/spatialopsbuild/include/spatialops/structured/stencil/OneSidedOperatorTypes.h:115:10: error: declaration of ‘SpatialOps::X2PosX {aka struct SpatialOps::OneSidedOpTypeBuilder<SpatialOps::Gradient, SpatialOps::OneSidedStencil2<SpatialOps::IndexTriplet<1, 0, 0> >, SpatialOps::SpatialField<LBMS::XVol, double> >}’
   struct OneSidedOpTypeBuilder;

以下是LBMS中的违规头文件(我们的代码库)。 Operators.h =&gt;

#ifndef LBMSOperators_h
#define LBMSOperators_h

#include <spatialops/structured/stencil/FVStaggeredBCOp.h>
#include <spatialops/structured/stencil/FVStaggeredOperatorTypes.h>
#include <spatialops/structured/stencil/OneSidedOperatorTypes.h>

...

#include <spatialops/structured/stencil/StencilBuilder.h>
#include <spatialops/Nebo.h>

/**
 *  \file  Operators.h
 *  \brief Defines operators for use in LBMS.
 */

namespace SpatialOps{
  class OperatorDatabase;   // forward declaration
}

namespace SpatialOps{
...

  typedef SpatialOps::OneSidedStencil2< SpatialOps::UnitTriplet<SpatialOps::XDIR>::type         > X2PlusT;
  typedef SpatialOps::OneSidedOpTypeBuilder<SpatialOps::Gradient, X2PlusT, LBMS::XVolField> X2PosX;
...

} // namespace SpatialOps
#endif // LBMSOperators_h

及其对应的cpp文件。 Operators.cpp =&gt;

#include "Operators.h"

...

//--- SpatialOps Headers ---//
#include <spatialops/OperatorDatabase.h>
#include <spatialops/structured/stencil/StencilBuilder.h>
#include <spatialops/Nebo.h>

using namespace SpatialOps;
...

namespace LBMS{
...

  void
  build_operators( const BundlePtr& bundle )
  {
    SpatialOps::OperatorDatabase& opDB = bundle->operator_database();

    const double dx = bundle->spacing(XDIR);
    NeboStencilCoefCollection<2> coefHalfDx2Plus   = build_two_point_coef_collection( -1.0/dx,  1.0/dx );
...

    opDB.register_new_operator<SpatialOps::X2PosX>( new SpatialOps::X2PosX( coefHalfDx2Plus  ) );
...

  }
} // namespace LBMS

这是来自库的标题,其中包含我尝试使用的运算符(同样,在LBMS中)。 OneSidedOperatorTypes.h =&gt;

#ifndef SpatialOps_structured_OneSidedOpTypes_h
#define SpatialOps_structured_OneSidedOpTypes_h

#include <spatialops/SpatialOpsDefs.h>
#include <spatialops/Nebo.h>

namespace SpatialOps{

  template<typename Op, typename StencilT, typename FieldT, typename Offset=IndexTriplet<0,0,0> >
  class OneSidedOpTypeBuilder;   // forward declaration
}
 /**
   * \struct OneSidedStencil2
   * \brief Support for one-sided stencils.
   * \tparam OpDir the unit vector (a IndexTriplet) that indicates the direction of offset for the stencil.
   * \tparam Offset (optional) the offset for the stencil.  <0,0,0> (default) results in a
   *         one-sided stencil that computes into the first stencil point.
   *         <1,0,0> would offset the stencil so that it effectively computes
   *         into the <-1,0,0> point.
   *
   * \par Example:
   * This code describes a 2-point stencil oriented in the (+x) direction.
   * \code{.cpp}
   * OneSidedStencil2< IndexTriplet<1,0,0> >
   * \endcode
   * It would look something like this:
   * \verbatim
             1 2 3
     Read :  o o o
     Write:  o
     \endverbatim
   *
   * \par Example:
   * This code describes a 2-point stencil oriented in the (-x) direction that
   * is offset in the (-x) direction.
   * \code{.cpp}
   * OneSidedStencil2< IndexTriplet<-1,0,0>, IndexTriplet<-1,0,0> >
   * \endcode
   * It would look something like this:
   * \verbatim
            n-2 n-1  n
     Read :  o   o
     Write:          o
     \endverbatim
   */
  template<typename OpDir, typename Offset=IndexTriplet<0,0,0> >
  struct OneSidedStencil2{
    typedef OpDir  DirT; ///< The orientation of the stencil (IndexTriplet)
    typedef typename Add<Offset,OpDir>::result Point2;
    typedef NEBO_FIRST_POINT(Offset)::NEBO_ADD_POINT(Point2)  StPtCollection;
  };

...

  /**
   *  \struct OneSidedOpTypeBuilder
   *  \ingroup optypes
   *  \brief Builds OneSidedDiv operator type from field type.
   *
   *  \tparam Op the basic operator type (e.g., Gradient, Interpolant)
   *  \tparam StencilT the stencil structure (e.g., OneSidedStencil3<IndexTriplet<0,-1,0>)
   *  \tparam FieldT the field that the operator applies to (e.g., SVolField)
   *  \tparam Offset the offset for the stencil.  <0,0,0> (default) results in a
   *          one-sided stencil that computes into the first stencil point.
   *          <1,0,0> would offset the stencil so that it effectively computes
   *          into the <-1,0,0> point.
   *
   *  \par Example Usage
   *  The following obtains the full type for a two-point, one-sided stencil
   *  shifted in the (-z) direction:
   *  \code
   *  typedef UnitTriplet<ZDIR>::type::Negate ZMinus;
   *  typedef OneSidedOpTypeBuilder<Gradient,OneSidedStencil2<ZMinus>,SVolField>::type OneSidedDiv2Z;
   *  \endcode
   *
   *  Note that we only provide fully specialized versions of this template
   *  so that unsupported operator types cannot be inadvertently formed.
   */
  template<typename Op, typename StencilT, typename FieldT, typename Offset=IndexTriplet<0,0,0> >
  struct OneSidedOpTypeBuilder;

#define BUILD_ONE_SIDED_OP_ACROSS_DIRS( Op, I1, I2, I3, StencilT, FieldT )                                  \
  template<> struct OneSidedOpTypeBuilder<Op,StencilT<IndexTriplet<I1,I2,I3> >,FieldT>{                     \
typedef NeboStencilBuilder<Op,StencilT<IndexTriplet<I1,I2,I3> >::StPtCollection, FieldT, FieldT>  type; \
  };

#define ONE_SIDED_OP_BUILDERS( Op, I1, I2, I3, FieldT )                      \
  BUILD_ONE_SIDED_OP_ACROSS_DIRS( Op, I1, I2, I3, OneSidedStencil2, FieldT ) \

...

#define BUILD_ONE_SIDED_STENCILS( FieldT )              \
  ONE_SIDED_OP_BUILDERS( Gradient,  1, 0, 0, FieldT )   \
  ONE_SIDED_OP_BUILDERS( Gradient, -1, 0, 0, FieldT )   \
  ONE_SIDED_OP_BUILDERS( Gradient,  0, 1, 0, FieldT )   \
  ONE_SIDED_OP_BUILDERS( Gradient,  0,-1, 0, FieldT )   \
  ONE_SIDED_OP_BUILDERS( Gradient,  0, 0, 1, FieldT )   \
  ONE_SIDED_OP_BUILDERS( Gradient,  0, 0,-1, FieldT )

...

BUILD_ONE_SIDED_STENCILS(   XVolField )

...

} // namespace SpatialOps

#endif // SpatialOps_structured_OneSidedOpTypes_h

如果我在Operators.h中转发声明,例如

namespace SpatialOps{
  template<typename Op, typename StencilT, typename FieldT>
  struct OneSidedOpTypeBuilder;   // forward declaration
}

然后我看到以下错误消息:     /scratch/local/prism_large/dac/debugging/LBMS2/src/operators/Operators.h:28:9:错误:重新定义'class Offset'的默认参数        class OneSidedOpTypeBuilder; //前向声明

或者,如果我在Operators.h中的forward declare中包含默认模板参数,

我收到以下错误:

[ 30%] Building CXX object src/CMakeFiles/lbms.dir/lbms/ProblemSolver.cpp.o
In file included from /scratch/local/prism_large/dac/debugging/LBMS2/src/transport/TransportEquationBase.h:40:0,
             from /scratch/local/prism_large/dac/debugging/LBMS2/src/lbms/ProblemSolver.h:38,
             from /scratch/local/prism_large/dac/debugging/LBMS2/src/lbms/ProblemSolver.cpp:29:
/scratch/local/prism_large/dac/debugging/LBMS2/src/operators/Operators.h:28:10: error: redefinition of default argument for ‘class Offset’
   struct OneSidedOpTypeBuilder;   // forward declaration
          ^
In file included from /scratch/local/prism_large/dac/debugging/nscbcbuild/include/nscbc/NSCBCToolsAndDefs.h:18:0,
             from /scratch/local/prism_large/dac/debugging/LBMS2/src/lbms/BCOptions.h:43,
             from /scratch/local/prism_large/dac/debugging/LBMS2/src/lbms/ProblemSolver.h:30,
             from /scratch/local/prism_large/dac/debugging/LBMS2/src/lbms/ProblemSolver.cpp:29:
/scratch/local/prism_large/dac/debugging/spatialopsbuild/include/spatialops/structured/stencil/OneSidedOperatorTypes.h:114:61: note: original definition appeared here
   template<typename Op, typename StencilT, typename FieldT, typename Offset=IndexTriplet<0,0,0> >

或者,如果我不包含默认模板参数,我将回到开头:

/scratch/local/prism_large/dac/debugging/LBMS2/src/operators/Operators.cpp: In function ‘void LBMS::build_operators(const BundlePtr&)’:
/scratch/local/prism_large/dac/debugging/LBMS2/src/operators/Operators.cpp:154:96: error: invalid use of incomplete type ‘SpatialOps::X2PosX {aka struct SpatialOps::OneSidedOpTypeBuilder<SpatialOps::Gradient, SpatialOps::OneSidedStencil2<SpatialOps::IndexTriplet<1, 0, 0> >, SpatialOps::SpatialField<LBMS::XVol, double> >}’
   opDB.register_new_operator<SpatialOps::X2PosX>( new SpatialOps::X2PosX( coefHalfDx2Plus  ) );
                                                                                                 ^
In file included from /scratch/local/prism_large/dac/debugging/LBMS2/src/operators/Operators.h:6:0,
             from /scratch/local/prism_large/dac/debugging/LBMS2/src/operators/Operators.cpp:1:
 /scratch/local/prism_large/dac/debugging/spatialopsbuild/include/spatialops/structured/stencil/OneSidedOperatorTypes.h:115:10: error: declaration of ‘SpatialOps::X2PosX {aka struct SpatialOps::OneSidedOpTypeBuilder<SpatialOps::Gradient, SpatialOps::OneSidedStencil2<SpatialOps::IndexTriplet<1, 0, 0> >, SpatialOps::SpatialField<LBMS::XVol, double> >}’
    struct OneSidedOpTypeBuilder;
           ^

如果我还有其他任何内容,请告诉我。一方面,我非常清楚包含所有内容的重要性,但另一方面,其中一些库非常大。

非常感谢!

1 个答案:

答案 0 :(得分:0)

在网上搜索OneSidedOpTypeBuilder课程,我找到了定义它的头文件。如果您查看该文件,您将在前向引用下方看到有一个用于创建模板特化的预处理器宏。

#define ONE_SIDED_OP_BUILDER( OP, STYLE, FIELD )                        \
    template<>                                                            \
    struct OneSidedOpTypeBuilder<OP,FIELD>{                               \
       typedef NeboStencilBuilder<OP,                                      \
                                  STYLE<OP,FIELD>::StPtCollection,         \
                                  FIELD,                                   \
                                  FIELD>                                   \
               type;                                                       \
    };

我认为您错误地使用OneSidedOpTypeBuilder并需要执行类似

的操作
ONE_SIDED_OP_BUILDER(SpatialOps::Gradient, X2PlusT, LBMS::XVolField);

X2PosX类型的typedef之前。