[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_;
};
|