错误:模板类型不完整

Error: Incomplete templated type

本文关键字:类型 错误      更新时间:2023-10-16

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

虽然我肯定在寻找解决方案,但我非常感谢你的解释,或者一个好指南的链接。我对高度模板化的OOP还很陌生,我很想了解什么是错误的,它是如何错误的,以及为什么。

所以我将尝试包含尽可能多的代码,而不给你们多个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=>

#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文件。操作员.cpp=>

#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=>

#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_larg/dac/debug/LBMS2/src/operators/operators.h:28:9:error:重新定义"class Offset"的默认参数class OneSidedOpTypeBuilder;//远期申报

或者,如果我在Operators.h,中的正向声明中包含默认模板参数

我得到以下错误:

[ 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;
           ^

如果还有什么需要我介绍的,请告诉我。一方面,我非常理解包含所有内容的重要性,但另一方面,这些图书馆中的一些相当大。

谢谢大家!

在web上搜索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之前。