在CRTP基类中声明派生类的静态constexpr实例时出错

时间:2016-07-31 04:44:25

标签: c++ constexpr crtp

我正在构建容器类型并尝试使用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

0 个答案:

没有答案