为什么这里要使用const静态变量odr-?

问题描述 投票:3回答:1

请考虑下面的代码。

class Test {
    public:
        static const int VALUE = 100;
};

std::tuple<int> foo(std::tuple<int> value) {
    return value;
}

int main()
{
    auto t = std::make_tuple(Test::VALUE); // This compiles fine
    auto t1 = foo(std::make_tuple(Test::VALUE)); // undefined reference to `Test::VALUE' linker error
}

根据另一个问题什么叫 "ODR-使用 "的东西?)和答案。

简而言之,odr-used的意思是某物(变量或函数)被使用在一个必须有其定义的上下文中。

在第一种情况下(变量 t)的变量 VALUE 不被使用,因为只需要它的值。但在第二种情况下,为什么代码不能编译?如果我把 t 而不是通过rvalue(?),代码就能正常编译。第二种情况与第一种情况有什么不同,为什么?VALUE 这里是否使用了odr-?

c++ c++14
1个回答
3
投票

make_tuple 取参数,通过 const int& (因为它是一个常数l值,而它需要一个 T&& 参数),而绑定一个引用到一个值是一个ODR用法。

这两种情况都是不正规的不需要诊断。例如在gcc的高优化水平下,整个程序都优化出来了,不会出现链接器错误,而在没有优化的情况下,两个语句都会给出链接器错误。

要想让它不属于ODR使用,可以将其转换为r值。

    // Various ways to force the lvalue-to-rvalue conversion
    auto t = std::make_tuple(int(Test::VALUE));
    auto t1 = foo(std::make_tuple((void(), Test::VALUE)));
    auto t2 = foo(std::make_tuple(+Test::VALUE));

(So std::make_tuple 需要 int&& 暂时性的)

或者你也可以做这样的定义 inline (最容易用 constexpr):

class Test {
    public:
        static constexpr int VALUE = 100;
};

2
投票

在第一种情况下(变量t),变量VALUE没有被odr-使用,因为只需要它的值。

不,它的值是需要的,而且是使用了ODR。

但是在第二种情况下,为什么代码不能编译?

因为你使用的编译器不够聪明,没有对第二段代码进行优化。比如说 这两行代码在gcc9.3和-O1下都能正常编译。.

© www.soinside.com 2019 - 2024. All rights reserved.