1

考虑这段代码:

#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.3and g++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;
}
4

1 回答 1

6

您可以避免在 上调用调用运算符pi,这样您的程序就不会使用它,编译器可以将其视为pi可以内联的值,因此不需要该数据成员的定义:static

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

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

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静态数据成员是整数或枚举类型,则其在类定义中的声明可以指定一个大括号或相等初始化器,其中作为赋值表达式的每个初始化器子句 都是一个常量表达式 (5.19) . 文字类型的静态数据成员可以在类定义中用说明符声明;如果是这样,它的声明应指定一个大括号或等式初始化器 ,其中作为赋值表达式的每个初始化器子句都是一个常量表达式。[ 注意:在这两种情况下,成员都可能出现在常量表达式中。——尾注]constexpr如果该成员在程序中被 odr-used (3.2) 使用并且命名空间范围定义不应包含初始化器,则该成员仍应在命名空间范围内定义

于 2013-05-09T17:43:31.420 回答