我正在构建容器类型并尝试使用Curiously Recurring Template Pattern重用尽可能多的代码。
这里是基本代码,在某些情况下编译,但在其他情况下不编译:
template<typename T, size_t N, typename ConcreteClass> struct _BaseClassOperators {
const ConcreteClass& operator+=(const ConcreteClass& other) {
ConcreteClass& self = static_cast<ConcreteClass&>(*this);
for(size_t i = 0; i < N; ++i) {
self.data[i] += other.data[i];
}
return self;
}
const ConcreteClass& operator+=(T value) {
ConcreteClass& self = static_cast<ConcreteClass&>(*this);
for(size_t i = 0; i < N; ++i) {
self.data[i] += value;
}
return self;
}
friend ConcreteClass operator+(ConcreteClass lhs, const ConcreteClass& rhs) {
lhs += rhs;
return lhs;
}
friend ConcreteClass operator+(ConcreteClass lhs, T value) {
lhs += value;
return lhs;
}
friend ConcreteClass operator+(T value, ConcreteClass rhs) {
rhs += value;
return rhs;
}
};
template<typename T, size_t N, typename ConcreteClass> struct _BaseClass : public _BaseClassOperators<T, N, ConcreteClass> {
};
template<typename T, typename ConcreteClass> struct _BaseClass<T, 3, ConcreteClass> : public _BaseClassOperators<T, 3, ConcreteClass> {
constexpr _BaseClass() : data { 0, 0, 0 } {}
constexpr _BaseClass(T first, T second, T third) : data { first, second, third } {}
explicit constexpr _BaseClass(T value) : data { value, value, value } {}
static constexpr ConcreteClass SomeInstance = ConcreteClass(ConcreteClass::SomeConstant, ConcreteClass::SomeConstant, ConcreteClass::SomeConstant);
T data[3];
};
template<typename T, size_t N> struct DerivedClass : public _BaseClass<T, N, DerivedClass<T, N>> {
using _BaseClass<T, N, DerivedClass>::_BaseClass;
static constexpr T SomeConstant = 0;
};
template<> struct DerivedClass<float, 3> : public _BaseClass<float, 3, DerivedClass<float, 3>> {
using _BaseClass::_BaseClass;
static constexpr float SomeConstant = 5.0f;
};
typedef DerivedClass<float, 3> DC3;
typedef DerivedClass<uint8_t, 3> DCI3;
当我使用+
运算符执行两个DC3
实例时,所有编译都没有问题:
DC3 do_something() {
return DC3::SomeInstance + DC3::SomeInstance;
}
int main(int argc, char* argv[]) {
do_something();
return 0;
}
当我更改do_something
以使用+
和DC3
致电float
运营商时,它会抱怨:
DC3 do_something() {
return DC3::SomeInstance + 0.5f;
}
的未定义引用
line number of do_something()...
:对_BaseClass&gt; :: SomeInstance&#39;
在这种情况下导致SomeInstance
未定义的原因是什么?
如果我在运算符类上定义了重载的operator[]
,并使用它来实现operator+=(const DerivedClass& other)
,将self.data[i]
更改为self[i]
,我也会得到同样的错误。
我还注意到,如果我将SomeInstance
定义为const
而不是constexpr
,并在模板正文之后初始化它(以模板化的方式),那么我就不会这样做。有任何问题。
如果这是一个错误,我在OSX上使用avr-g ++(gcc)4.8.1,并定义了-std=gnu++11
。