与 complex.h 一起使用时对静态 const double 的未定义引用

Posted

技术标签:

【中文标题】与 complex.h 一起使用时对静态 const double 的未定义引用【英文标题】:Undefined reference to static const double when used with complex.h 【发布时间】:2016-07-07 10:17:15 【问题描述】:

这是最少的代码:

#include <iostream>
#include <complex>

using namespace std;

class Test 
    static const double dt = 0.1;
public:
    void func();
;

void Test::func() 
    cout << dt << endl; // OK!
    cout << dt*complex<double>(1.0, 1.0) << endl; // Undefined reference


int main() 
    Test a;
    a.func();

注明的行给出了undefined reference to `Test::dt'。每次我想将复数与dt 相乘时,我都可以创建一个临时变量,但这很不方便,因为我在代码中将许多静态 const 成员与复数相乘。

我的猜测是,当dt 与复数相乘时,由于某种原因,它需要dt 的地址(即&amp;dt,这看起来很奇怪。

任何想法为什么会发生此错误以及如何使它比在每次我想将其与复数相乘之前执行double temp = dt; 更优雅?

【问题讨论】:

这段代码不应该编译。删除static @HansPassant 是的,它不编译,它给出了未定义的引用。我需要静态常量变量。 不,由于static 关键字,它无法编译:error: ‘constexpr’ needed for in-class initialization of static data member ‘const double Test::dt’ of non-integral type 在修复此编译错误后,我可以重现未定义的引用错误。这在我看来确实像一个编译器错误。 它没有链接,这是一个与编译错误非常不同的问题。否则准确,无法链接。请务必命名您使用的编译器,以便遇到相同错误的任何人都知道如何处理它。 我看到 gcc 6.1.1 的未定义引用错误。这看起来像一个 gcc 编译器错误。 【参考方案1】:

...如何使它工作...?

#include <iostream>
#include <complex>

using namespace std;

class Test 
    static const double dt;
public:
    void func();

;

//move initialization outside of class
const double Test::dt = 0.1; 

void Test::func() 
    cout << dt << endl; // OK!
    cout << dt*complex<double>(1.0, 1.0) << endl; // Undefined reference



int main() 
    Test a;
    a.func();

或(请参阅this question 了解说明)

class Test 
        static const double dt = 0.1;
    public:
        void func();

;
const double Test::dt;

或(与上面的技巧相同,但使用 c++11 的 constexpr

class Test  
         static constexpr double dt = 0.1;
    public:   
         void func();    

;                      
constexpr double Test::dt;

任何想法为什么会发生此错误...?

来自here:

如果声明了整数或枚举类型的静态数据成员 const (而不是 volatile),它可以用初始化器初始化 每个表达式都是一个常量表达式,就在 类定义...

如果静态数据成员是 intenum 类型并声明为 const,则可以在类定义内初始化静态数据成员,即你的情况。 (更多信息请参见this answer)

为什么它似乎适用于第一行?好吧,用 clang 编译我得到了:

警告:'const 类型的静态数据成员的类内初始化程序 double' 是一个 GNU 扩展

所以这个浮点类型初始化是 gcc 编译器的扩展,这个扩展可能不适用于期望引用类型参数的函数(现在只是一个猜测)。

另请注意,这仅适用于 c++98(c++11 具有解决此问题的 constexpr 关键字)

【讨论】:

嘿,我尝试在 OP 的代码中使用 static constexpr 而不是 static const,但未定义的引用仍然存在。 关于您的最后一次编辑:如果您切换const->constexpr,那么它会起作用,并且几乎正是我在原始帖子中所要求的。【参考方案2】:

您已经声明了Test::dt,但没有在某处定义它。如果你决定在类声明之外定义一些东西——你应该保持一致:

#include <iostream>
#include <complex>

using namespace std;

class Test 
    static const double dt;
    public:
    void func();
;

void Test::func() 
    cout << dt << endl; // OK!
    cout << dt*complex<double>(1.0, 1.0) << endl; // Undefined reference


const double Test::dt = 0.1;

int main() 
    Test a;
    a.func();

【讨论】:

这会起作用,但由于我有很多常量,将初始化保留在标题中会更方便和信息丰富。目前我还是更喜欢临时变量解决方案。 在您的情况下,简单的enum 会更好吗? 显然enum 在与复数相乘时也会出错。【参考方案3】:
#include <iostream>
#include <complex>

using namespace std;

class Test 
    static const double dt;
    public:
    void func();
;

void Test::func() 
    cout << dt << endl; // OK!
    cout << dt*complex<double>(1.0, 1.0) << endl; // Undefined reference


const double Test::dt = 0.1;

int main() 
    Test a;
    a.func();

【讨论】:

以上是关于与 complex.h 一起使用时对静态 const double 的未定义引用的主要内容,如果未能解决你的问题,请参考以下文章

Hive动态分区与静态分区,数据插入,区别

C++ 编程习惯与编程要点

c_cpp complex.h

libcvd - 编译 C++ 时对“x ...”的未定义引用

漫谈C++:良好的编程习惯与编程要点

漫谈C++:良好的编程习惯与编程要点