1

我试图在编译时生成数字并尝试模板。但是,当我使用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 staticenum

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++标准是否提到过这个问题。

回答

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

是它的工作原理。有问题的代码也用'-std = C++ 17'编译。 – xris

+0

还有一个问题:为什么'enum'有效,似乎enum从来没有定义过。 – xris

+0

@xris因为enum不是'static const'值 - 它是一个r值表达式。所以一个实例是在使用点制造的。 –

1

尝试(在你的第一个例子)将