我正在尝试在编译时生成数字并尝试模板。但是当我使用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 ++标准是否提到了这一点。
答案 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;