使用g ++ 4.7.3和g ++ 4.8进行未定义的引用?

时间:2013-05-09 17:40:59

标签: c++ c++11 compiler-errors g++ undefined-reference

考虑以下代码:

#include <iostream>
#include <array>

template <typename Type>
struct Constant
{
    constexpr Constant(const Type source) : _data({{source}}) {;}
    constexpr Constant(const std::array<Type, 1> source) : _data(source) {;}
    constexpr Constant<Type> operator()() const {return _data;}
    constexpr operator Type() const {return _data[0];}
    const std::array<Type, 1> _data;
    static constexpr Constant<Type> pi = 3.1415926535897932384626433832795028841971693993751058209749445L;
};

int main(int argc, char* argv[])
{
    std::cout<<Constant<double>::pi()<<std::endl;
    return 0;
}

我收到g++4.7.3g++4.8.0的编译错误(这是对pi的未定义引用(抱歉用法语)):

/tmp/cctdvPfq.o: dans la fonction « main »:
main.cpp:(.text.startup+0xd): référence indéfinie vers « Constant<double>::pi »
collect2: erreur: ld a retourné 1 code d'état d'exécution

由于我的系统是全新安装(第一次使用g++4.7.3g++4.8.0),我不知道它是来自我的系统配置还是来自编译器。如果它来自编译器,问题出在哪里?

编辑:为什么这有效? (没有数组的版本)

#include <iostream>
#include <array>

template <typename Type>
struct Constant
{
    constexpr Constant(const Type source) : _data(source) {;}
    constexpr Constant<Type> operator()() const {return _data;}
    constexpr operator Type() const {return _data;}
    const Type _data;
    static constexpr Constant<Type> pi = 3.1415926535897932384626433832795028841971693993751058209749445L;
};

int main(int argc, char* argv[])
{
    std::cout<<Constant<double>::pi()<<std::endl;
    return 0;
}

1 个答案:

答案 0 :(得分:6)

您可以避免在pi上调用调用操作符,以便程序不会 odr-used ,并且编译器可以将pi视为值可以内联,因此不需要static数据成员的定义

std::cout << Constant<double>::pi << std::endl;
//                             ^^

或者,您可以继续调用pi的调用运算符,并在命名空间范围内提供静态数据成员的定义,并使用Constant<double>的调用运算符与原始代码一样:

template <typename Type>
struct Constant
{
    // ...
    static constexpr Constant<Type> pi = /* ... */;
};

template<typename Type>
constexpr Constant<Type> Constant<Type>::pi;

根据C ++ 11标准的第9.4.2 / 3段:

  

如果非易失性const静态数据成员是整数或枚举类型,则其在类中的声明   定义可以指定大括号或等于初始值,其中每个 initializer-clause 赋值表达式   是一个常量表达式(5.19)。可以在。中声明文字类型的静态数据成员   使用constexpr说明符的类定义;如果是这样,其声明应指定大括号或等于初始值   其中作为赋值表达式的每个 initializer-clause 都是一个常量表达式。 [注意:两者都有   在这些情况下,成员可能出现在常量表达式中。 -end note] 仍然要定义成员   如果在程序中使用odr-used(3.2)并且命名空间作用域定义不在,则在命名空间作用域中   包含初始化程序