[GD-Windows] LNK1179: duplicate COMDAT (templates, vc2003)
Brought to you by:
vexxed72
From: Jon W. <hp...@mi...> - 2007-03-23 00:02:44
|
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_; }; |