繁体   English   中英

将静态constexpr类成员分配给运行时变量

[英]Assign static constexpr class member to runtime variable

我知道有很多类似的问题,但不知何故有不同的问题。 这是关于以下情况:

#include <iostream>
#include <array>

template<typename T> class MyClass
{
public:
    static constexpr std::array<T,4> ARRAY {{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;
}

据我所知constexpr是编译时常量。 因此编译器可以进行一些计算,例如计算VALUE 另外,我可以明确地定义一个constexpr std::array<,> ,我可以从中将值分配给运行时变量。 我希望编译器已将value = 4设置为可执行程序,以避免加载操作。 但是,我不能直接从静态成员分配,得到错误

undefined reference to `MyClass<int>::ARRAY'
clang-3.7: error: linker command failed with exit code 1

这对我来说没有意义,因为它可以通过另一个constexpr变量的中间步骤来完成。

所以我的问题是:为什么不能将类的静态constexpr成员分配给运行时变量?

注意:在我的MWE中,类是模板类,不会影响错误。 但是,我最初对这个特殊情况感兴趣,对于非模板类,我希望它更通用。

(编译器是clang++g++ ,- -std=c++11 - 它们给出相同的错误)

编辑:@Bryan Chen:忘了输出线。 现在加入。

undefined reference是链接器错误。 规则是如果变量使用了odr,那么它必须有一个定义。 这甚至适用于constexpr变量。

与大多数ODR规则一样,违反它是未定义的行为,无需诊断(这可以解释为什么您没有看到对该值的某些用途的诊断)。

要修复错误,请在类外添加定义:

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

由于它是一个模板,你实际上可以将它放在标题中,而不是通常情况下定义恰好放在一个.cpp文件中。


这里的主要问题是ARRAY[0]是否算作使用 根据这篇详细的文章 ,在C ++ 11和C ++ 14中,对数组进行索引确实算作odr-use ,但是对于C ++ 14提交的DR 1926改变了这种情况

然而 ,这是在讨论内置数组。 IDK是否同样的理由适用于std::array ,我发现[basic.def.odr] / 3的文本难以理解。 根据cppreference非正式定义std::array::operator[]会导致数组使用odr ,因为它的返回值会绑定对数组的引用。

出于这个原因,我总是从constexpr函数返回constexpr对象。

修改后的代码。 请注意,由于std::array<>的c ++ 14缺陷,您必须返回const std::array以允许operator[]工作。

#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;
}

预期成绩:

20
4

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM