模板元编程静态成员函数无法获取类的const静态值

时间:2017-08-30 21:41:25

标签: c++ c++11 templates template-meta-programming static-members

我正在尝试在编译时生成数字并尝试模板。但是当我使用constexpr static成员变量而不是enum时,在static成员函数中我试图将其推入std::vector时,编译器告诉我链接器是无法链接。

例如,这是一个计算n的阶乘的简单程序。

#include <iostream>
#include <vector>

template <uint64_t n> struct factorial {
    constexpr static uint64_t value = factorial<n - 1>::value * n;
    static void put(std::vector<uint64_t> &v) {
        factorial<n - 1>::put(v);
        v.push_back(value);
    }
};

template <> struct factorial<0> {
    constexpr static uint64_t value = 1;
    static void put(std::vector<uint64_t> &v) {
        v.push_back(1);
    }
};

int main() {
    using namespace std;
    vector<uint64_t> v;
    factorial<10>::put(v);
    for (auto fact: v)
        cout << fact << endl;
    return 0;
}

这会产生g ++ 7.1和clang 4.0的链接失败信息,所以我认为这不是一个bug。当我将constexpr static更改为enum

template <uint64_t n> struct factorial {
    enum { value = factorial<n - 1>::value * n };
    static void put(std::vector<uint64_t> &v) {
        factorial<n - 1>::put(v);
        v.push_back(value);
    }
};

template <> struct factorial<0> {
    enum { value = 1 };
    static void put(std::vector<uint64_t> &v) {
        v.push_back(1);
    }
};

它编译和链接并运行得很好。

我想知道C ++标准是否提到了这一点。

2 个答案:

答案 0 :(得分:3)

据我所知,std::vector<T>::push_back()的签名为void push_back(V const&)

因此,我们正在考虑价值。

因此它必须有一个地址,它不会因为它从未被定义(虽然这对我来说似乎有些不合逻辑) - 也许这在c ++ 17中得到修复?

可以通过复制并推送它来编译:

#include <iostream>
#include <vector>

template <uint64_t n> struct factorial {
    constexpr static uint64_t value = factorial<n - 1>::value * n;
    static void put(std::vector<uint64_t> &v) {
        factorial<n - 1>::put(v);
        auto vcpy = value;   // *** HERE ***
        v.push_back(vcpy);
    }
};

template <> struct factorial<0> {
    constexpr static uint64_t value = 1;
    static void put(std::vector<uint64_t> &v) {
        v.push_back(1);
    }
};

int main() {
    using namespace std;
    vector<uint64_t> v;
    factorial<10>::put(v);
    for (auto fact: v)
        cout << fact << endl;
    return 0;
}

答案 1 :(得分:1)

尝试(在第一个示例中)添加

template <uint64_t n>
constexpr uint64_t factorial<n>::value;