LNK1179: duplicate COMDAT (templates, vc2003)

Jon Watte <[email protected]> Thu, 22 Mar 2007 17:02:47 -0700
Newsgroups gmane.games.devel.windows
Message-ID <[email protected]>
We're using VC 2003 (can't upgrade to 2005 just yet, although it's on 
the long-term map).

When building a certain file, which uses some moderately simple 
templates, I get a linker error about duplicate COMDAT sections for a 
specific template instantiation. It seems as if the function in question 
is being instantiated twice in the same obj file by the compiler.

Googling for this turns up a bunch of errors in VC6, which have nothing 
to do with this problem, and a few people who had problems with some bg 
in the incremental linker. I've turned off incremental linking for this 
library (I'm building a DLL), and the error still happens.


I'm looking for the following things:

1) A fix for a known problem.
2) Suggestions for how to work around this problem.
3) A drinking buddy who has the same problem and can relate to the sorrow.


The code looks somewhat like:

namespace impl_DX9 {

template<typename Container, typename Type, Type (Container::*Field)[]>
class FieldArrayAccessor {
  public:
    typedef Container ContainerType;
    typedef Type FieldType;
    Type const *Access(Container const &c) { return c.*Field; }
};

//  Match SasCamera
struct SasCamera {
  Mat4Float        worldtoview;    //  will always be the identity transform
  Mat4Float        projection;
  float            nearfarclipping[2];
  FastTriple       position;       //  because the camera is always the 
center of the world view, it's always 0,0,0
};


I have tried making the Access() functions be inline static, and regular 
static as well (in fact, they started life out being inline static); I 
still get this error.

The three uses of the template in the file look like this:


  return new WholeArraySetter<FieldArrayAccessor<
      SasCamera, float, reinterpret_cast<float 
(SasCamera::*)[]>(&SasCamera::nearfarclipping)>
      >(pb, cam, 2);

      setter_ = new ArrayItemSetter<FieldArrayAccessor<
          SasCamera, float, reinterpret_cast<float 
(SasCamera::*)[]>(&SasCamera::nearfarclipping)>
          > (this, core_->camera_, l);

  setter_ = new WholeArraySetter<FieldArrayAccessor<
      SasSkeleton, pit::Mat4Float, reinterpret_cast<pit::Mat4Float 
(SasSkeleton::*)[]>(
      &SasSkeleton::meshtojointtoworld)> >(this, core_->skeleton_, 
&core_->skeleton_.get().numjoints);


The templates that invoke the actual instance (Access function) look 
like (look at the Update() functions):

template<typename Accessor>
class WholeArraySetter : public IValueSetter {
  public:
    //  When the count is fixed, stuff it in a member, and point the 
pointer at that.
    WholeArraySetter(ParameterBinder *bind, DirtyState<typename 
Accessor::ContainerType> const &ds, int cnt)
        : bind_(bind), ds_(ds), cnt_(cnt) { cntptr_ = &cnt_; }
    //  When the count is variable, bind using a pointer. The 'cnt' is 
not used.
    WholeArraySetter(ParameterBinder *bind, DirtyState<typename 
Accessor::ContainerType> const &ds, int const *cnt)
        : bind_(bind), ds_(ds), cntptr_(cnt) { cnt_ = -1; }
    virtual void Dispose() { delete this; }

    virtual HRESULT Update(ID3DXEffect *fx) {
      if (!ds_.dirty()) {
        return S_OK;
      }
      //later: handle type casting (float->int, etc).
      return fx->SetValue(bind_->param_, Accessor().Access(ds_.get()),
          sizeof(typename Accessor::FieldType) * *cntptr_);
    }

    ParameterBinder *bind_;
    DirtyState<typename Accessor::ContainerType> const &ds_;
    int cnt_;
    int const *cntptr_;
};

template<typename Accessor>
class ArrayItemSetter : public IValueSetter {
  public:
    //  When the count is fixed, stuff it in a member, and point the 
pointer at that.
    ArrayItemSetter(ParameterBinder *bind, DirtyState<typename 
Accessor::ContainerType> const &ds, int cnt)
        : bind_(bind), ds_(ds), cnt_(cnt) {}
    virtual void Dispose() { delete this; }

    virtual HRESULT Update(ID3DXEffect *fx) {
      if (!ds_.dirty()) {
        return S_OK;
      }
      //later: handle type casting (float->int, etc).
      return fx->SetValue(bind_->param_, Accessor().Access(ds_.get()) + 
cnt_,
          sizeof(typename Accessor::FieldType));
    }

    ParameterBinder *bind_;
    DirtyState<typename Accessor::ContainerType> const &ds_;
    int cnt_;
};



-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Gamedevlists-windows mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/gamedevlists-windows
Archives:
http://sourceforge.net/mailarchive/forum.php?forum_id=555