【问题标题】:Static constants of templated class模板类的静态常量
【发布时间】:2014-03-17 18:21:05
【问题描述】:

我一直在玩 gcc 4.8.2 中的模板类和常量,遇到了一个有趣的链接器错误:

#include <iostream>
using namespace std;

template <class T, int m>
class A {
public:
  static const T param = m;
  T value;

  A(const T &value, const T &dummy = T()) : value(value) {}
};

// Works with this
// template <class T, int m>
// const T A<T, m>::param = m;    

template <class T, int m>
A<T, m> operator +(const A<T, m> &a, const A<T, m> &b) {
  if (a.param != b.param) exit(1);

  // Works if I replace a.param with 0
  return A<T, m>(a.value + b.value, a.param);
}

int main() {
  A<int, 2> v = A<int, 2>(1) + A<int, 2>(2);
  cout << v.value << endl;
  return 0;
}

在当前状态下编译代码会出现链接器错误,告诉我A::param 未定义。

在 Visual Studio 2008 中也尝试此代码,它编译和链接没有任何问题。在 gcc 上,当我使用 param 常量的外部声明,或者如果我将 a.param 替换为 0 或在指示的行上没有任何内容时,它会编译。

我不明白的是为什么包含if 语句的行可以使用a.param 而不会出现编译错误,而我不能在没有外部声明的情况下将a.param 传递给构造函数。

所以我的问题是:我什么时候需要在外部声明paramif 语句中的访问和构造函数调用有什么区别?我测试的两个编译器中的哪一个在这里做“正确”的事情,哪一个扩展了标准?

玩了一会儿,我意识到当我将 -O2 标志指定给 g++ 时它也可以工作。

【问题讨论】:

    标签: c++ gcc gcc4


    【解决方案1】:
    template <class T, int m>
    class A {
    public:
      static const T param = m;
      T value;
    
      A(const T &value, const T &dummy = T()) : value(value) {}
    };
    
    // Works with this
    // template <class T, int m>
    // const T A<T, m>::param = m;
    
    //gotta define it here!
    template <class T, int m>
    const T A<T, m>::param;
    
    template <class T, int m>
    A<T, m> operator +(const A<T, m> &a, const A<T, m> &b) {
      if (a.param != b.param) exit(1);
    
      // Works if I replace a.param with 0
      return A<T, m>(a.value + b.value, a.param);
    }
    
    int main() {
      A<int, 2> v = A<int, 2>(1) + A<int, 2>(2);
      std::cout << v.value << std::endl;
      return 0;
    }
    

    来自here

    如果静态数据成员是 const 整数或 const 枚举类型,您可以在静态数据成员的声明中指定常量初始化器。这个常量初始化器必须是一个整数常量表达式。请注意,常量初始值设定项不是定义。您仍然需要在封闭的命名空间中定义静态成员。

    在正常工作的情况下,编译器不合规。微软不合规,因为微软几乎从不合规,带有 -O2 的 g++ 有点有趣,但无论哪种情况,你都没有定义!

    编辑: 根据经验,我总是在类之外定义我的静态常量成员变量,因为这样我就不必记住它了。在这种情况下,如果 T 不是整数类型(例如浮点数),则 A 类将无效。因此,我不会围绕例外做任何模式,而是倾向于坚持围绕规则使用我的模式。

    【讨论】:

    • 感谢您的澄清和良好的经验法则!
    猜你喜欢
    • 1970-01-01
    • 2016-03-05
    • 2019-05-10
    • 1970-01-01
    • 1970-01-01
    • 2013-07-11
    • 1970-01-01
    • 2015-03-06
    • 1970-01-01
    相关资源
    最近更新 更多