Assign static constexpr class member to runtime variable

我怕爱的太早我们不能终老 提交于 2019-11-30 19:33:56
M.M

The undefined reference is a linker error. The rule is that if a variable is odr-used then it must have a definition. This applies even for constexpr variables.

Like most ODR rules, violating it is undefined behaviour with no diagnostic required (which could explain why you saw no diagnostic for some of your uses of the value).

To fix the error, add a definition outside the class:

template<typename T> constexpr std::array<T,4> MyClass<T>::ARRAY;

Since it is a template you can actually put this in the header, as opposed to the usual case where the definition goes in exactly one .cpp file.


The main issue here is whether ARRAY[0] counts as odr-use. According to this detailed post, in C++11 and C++14, indexing an array does count as odr-use , but this was changed by DR 1926 filed against C++14 to not be odr-use.

However, that is talking about builtin arrays. IDK whether the same rationale applies to std::array, I find the text of [basic.def.odr]/3 hard to understand. According to the informal definition on cppreference, std::array::operator[] would cause odr-use of the array because its return value binds a reference to the array.

For this reason I always return constexpr objects from a constexpr function.

Modified code below. Note that due to a c++14 deficiency in std::array<> you must return a const std::array in order to allow operator[] to work.

#include <iostream>

#include <iostream>
#include <array>

template<typename T> class MyClass
{
public:
    static constexpr const std::array<T,4> ARRAY() { return {4, 3, 1, 5}; };
};

int main()
{
    constexpr std::array<int, 4> my_array(MyClass<int>::ARRAY()); // works fine -> can use the ARRAY to initialize constexpr std::array

    constexpr int VALUE = 5 * MyClass<int>::ARRAY()[0]; // works also fine

    int value;
    value = my_array[0]; // can assign from constexpr
    value = MyClass<int>::ARRAY()[0]; // undefined reference to `MyClass<int>::ARRAY

    std::cout << VALUE << std::endl;
    std::cout << value << std::endl;

    return 0;
}

expected results:

20
4
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!