是否使用了静态constexpr变量odr? [英] Is static constexpr variable odr-used?

查看:87
本文介绍了是否使用了静态constexpr变量odr?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给出以下代码,是否使用了Foo::FOO1 ODR?

Giving below code, is Foo::FOO1 ODR-used or not?

#include <iostream>
#include <map>
#include <string>

class Foo
{
public:
    static constexpr auto FOO1 = "foo1";
    void bar();
};

void Foo::bar()
{
    const std::map<std::string, int> m = {
        {FOO1, 1},
    };
    for (auto i : m)
    {
        std::cout << i.first << " " << i.second << std::endl;
    }
}

int main()
{
    Foo f;
    f.bar();
    return 0;
}

使用-O1或更高版本编译代码,可以,但是如果使用-O0编译,则会出现以下错误(请参阅

Compiling the code with -O1 or above, it is OK, but if compile with -O0, I get below error (see coliru example:

undefined reference to `Foo::FOO1'

表示它已使用ODR.是哪一个?

which indicates that it is ODR-used. Which is it?

我知道上面的代码可以用-O很好地构建,但是在 a中真实(且更复杂)的情况:

I know the above code is built fine with -O, but in a real (and more complex) case:

  • 代码可以通过-O2进行编译和链接
  • 代码获得上述undefined reference错误LinkTimeOptimization(-O2 -flto)
  • The code compiles and links fine with -O2
  • The code gets the above undefined reference error LinkTimeOptimization (-O2 -flto)

那么这表明优化(-O)和LinkTimeOptimization(-flto)都会影响ODR使用规则吗?在C ++ 14和C ++ 17之间会发生变化吗?

So it indicates that both optimizations (-O) and LinkTimeOptimization (-flto) would affect ODR-use rule? Does this change between C++14 and C++17?

推荐答案

规则为

变量x的名称显示为可能评估的表达式exex 除非将左值应用于右值已使用转换为x会产生一个常量表达式,该常量表达式不会调用任何非平凡函数,并且如果x是对象,则ex是表达式e的潜在结果集中的一个元素,其中左值到右值转换([conv.lval])应用于e,或者e是舍弃值表达式([expr.prop]).

A variable x whose name appears as a potentially-evaluated expression ex is odr-used by ex unless applying the lvalue-to-rvalue conversion to x yields a constant expression that does not invoke any non-trivial functions and, if x is an object, ex is an element of the set of potential results of an expression e, where either the lvalue-to-rvalue conversion ([conv.lval]) is applied to e, or e is a discarded-value expression ([expr.prop]).

显然第一部分是满意的(FOO1constexpr,所以从左值到右值的转换确实会产生一个常量表达式而不调用非平凡的函数),但是第二部分是吗?

The first part is obviously satisfied (FOO1 is constexpr so the lvalue-to-rvalue conversion does yield a constant expression without invoking non-trivial functions), but is the second?

我们正在构建map.相关的那里的构造子采用initializer_list<value_type>,即initializer_list<pair<const string, int>>. pair具有许多构造函数,但是在这里调用的是:

We're constructing a map. The relevant constructor there takes an initializer_list<value_type>, which is to say an initializer_list<pair<const string, int>>. pair has a bunch of constructors, but the one that would be invoked here is:

template <class U1, class U2>
constexpr pair(U1&& x, U2&& y); // with U1 = char const*&, U2 = int

这里的重要部分是我们不是直接构造string,而是要通过pair的转换构造函数,其中涉及到对FOO1的引用的绑定.这是一个奇怪的用途.这里没有左值到右值的转换,这也不是一个丢弃值的表达式.

The important part here is that we're not directly constructing a string, we're going through this converting constructor of pair, which involves binding a reference to FOO1. That's an odr-use. There's no lvalue-to-rvalue conversion here, nor is this a discarded-value expression.

基本上,当您使用某物的地址时,这是一种奇怪的用法-它必须具有定义.因此,您必须添加一个定义:

Basically, when you take the address of something, that's an odr-use - it has to have a definition. So you have to add a definition:

constexpr char const* Foo::FOO1;

请注意,另一方面:

std::string s = FOO1;

不会会成为odr用途.在这里,我们直接调用带有char const*参数的构造函数,该参数将是从左值到右值的转换.

would not be an odr-use. Here we're directly invoking a constructor taking a char const* parameter, which would be an lvalue-to-rvalue conversion.

在C ++ 17中,我们在> dcl.constexpr] :

In C++17, we got this new sentence in [dcl.constexpr]:

用constexpr说明符声明的函数或静态数据成员隐式是内联函数或变量([dcl.inline]).

A function or static data member declared with the constexpr specifier is implicitly an inline function or variable ([dcl.inline]).

这不会更改odr的使用,FOO1仍会在您的程序中使用odr.但这确实使FOO1隐式成为内联变量,因此您不必显式为其添加定义.很酷.

This doesn't change anything about odr-use, FOO1 is still odr-used in your program. But it does make FOO1 implicitly an inline variable, so you don't have to explicitly add a definition for it. Pretty cool.

还请注意,仅仅因为程序进行编译和链接并不意味着没有定义的变量未被使用.

Note also that just because a program compiles and links does not mean that a variable that lacks a definition was not odr-used.

那么这表明优化(-O)和LinkTimeOptimization(-flto)都会影响ODR使用规则吗?

So it indicates that both optimizations (-O) and LinkTimeOptimization (-flto) would affect ODR-use rule?

他们没有.这样的优化很酷.

They do not. Optimizations are cool like that.

这篇关于是否使用了静态constexpr变量odr?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆