模板元编程静态成员函数无法获得const静态类的值
问题描述:
我试图在编译时生成数字并尝试模板。但是,当我使用constexpr static
成员变量而不是enum
,并且在static
成员函数中,我尝试将它推入std::vector
时,编译器告诉我链接程序无法链接。模板元编程静态成员函数无法获得const静态类的值
例如,这里有一个简单的程序来计算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和铛4.0,所以我认为这不是一个错误。而当我改变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++标准是否提到过这个问题。
答
至于我可以告诉大家,那是因为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;
}
答
尝试(在你的第一个例子)将
是它的工作原理。有问题的代码也用'-std = C++ 17'编译。 – xris
还有一个问题:为什么'enum'有效,似乎enum从来没有定义过。 – xris
@xris因为enum不是'static const'值 - 它是一个r值表达式。所以一个实例是在使用点制造的。 –