Constexpr satır içi anlamına mı geliyor?


105

Aşağıdaki satır içi işlevi düşünün:

// Inline specifier version
#include<iostream>
#include<cstdlib>

inline int f(const int x);

inline int f(const int x)
{
    return 2*x;
}

int main(int argc, char* argv[])
{
    return f(std::atoi(argv[1]));
}

ve constexpr eşdeğer sürümü:

// Constexpr specifier version
#include<iostream>
#include<cstdlib>

constexpr int f(const int x);

constexpr int f(const int x)
{
    return 2*x;
}

int main(int argc, char* argv[])
{
    return f(std::atoi(argv[1]));
}

Sorum şu: constexprtanımlayıcı, inlinebir constexprişleve sabit olmayan bir argüman iletilirse , derleyicinin, tanımlayıcı bildirimine yerleştirilmiş inlinegibi işlevi deneyeceği anlamında tanımlayıcıyı ima ediyor inlinemu?

C ++ 11 standardı bunu garanti ediyor mu?


5
'Derleyici işlevi satır içi yapmaya çalışacak', tanımlayıcının yaptığı şey değildir inline. (Ya da belki ifadenizi yanlış anladım.)
Luc Danton

5
inlineBelirteci artık bir ilgisi vardır inlining
K-ballo

2
Soru inline, doğrudan satır içi ile ilgili yanlış varsayıma dayanır . Yani hayır, bu anlamda var olmadığından constexpr, inlinebelirtici bu anlamda belirticiyi ima etmez.
Christian Rau

Yanıtlar:


139

Evet ([dcl.constexpr], C ++ 11 standardında §7.1.5 / 2): "constexpr işlevleri ve constexpr oluşturucuları örtük olarak satır içi (7.1.2)."

Bununla birlikte, inlinebelirticinin, bir derleyicinin bir işlevi satır içi olarak genişletip genişletmeyeceği üzerinde gerçekten çok az (varsa) etkisi olduğunu unutmayın. Bununla birlikte, tek tanım kuralını etkiler ve bu bakış açısıyla, derleyicinin bir constexprişlev olarak bir inlineişlev için aynı kuralları izlemesi gerekir .

Ayrıca, constexprima etmeksizin, C ++ 11'deki işlevlerin inlinekurallarının constexpr, satır içi genişletme için genellikle iyi adaylar olacak kadar basit olmalarını gerektirdiğini de eklemeliyim (birincil istisna özyinelemeli olanlar). Ancak o zamandan beri kurallar giderek gevşedi, bu nedenle constexprönemli ölçüde daha büyük, daha karmaşık işlevlere uygulanabilir.


Fikir sabit ifadelerin derleme zamanında değerlendirildiği düşünüldüğünde, constexprişlevlerin çoğu kullanımının herhangi bir kod üretmeye neden olmayacağını düşünüyorum ...
Kerrek SB

11
@KerrekSB constexprişlevleri potansiyel olarak derleme zamanında değerlendirilir. Ancak C ++ 14 standardı, büyük olasılıkla çalışma zamanında çağrılacak olanlarla doludur. Örneğin:std::array<T,N>::at
Eponymous

@Eponymous evet, ancak yalnızca en çok indirgenmiş biçim işlem kodu olarak kalacaktır. Örneğin: bağlı denetimler, kod yolları sabit olduğundan derleme zamanında değerlendirilecektir. Ancak döndürülen değer * (data + offset)
v.oddou

16

constexprinlinestatik olmayan değişkenleri ima etmez (C ++ 17 satır içi değişkenler)

İken constexprima etmez inlinefonksiyonlar için, bu ++ 17 satır içi değişkenler C düşünüldüğünde statik olmayan değişkenler için bu etkisi yoktur.

Örneğin, şu adresten yayınladığım asgari örneği alırsanız: Satır içi değişkenler nasıl çalışır? ve kaldır, inlinesadece bırak constexpr, sonra değişken birden çok adres alır, bu da satır içi değişkenlerin kaçındığı en önemli şeydir.

constexpr ancak statik değişkenler dolaylı olarak statiktir.

İşlevleri constexprifade eden minimal örnekinline

Şu adreste bahsedildiği gibi: https://stackoverflow.com/a/14391320/895245 ana etkisi inlinesatır içi değil, bir işlevin birden fazla tanımına izin vermektir, standart alıntı: Bir C ++ başlık dosyası uygulamayı nasıl içerebilir?

Aşağıdaki örnekle oynayarak bunu gözlemleyebiliriz:

main.cpp

#include <cassert>

#include "notmain.hpp"

int main() {
    assert(shared_func() == notmain_func());
}

notmain.hpp

#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP

inline int shared_func() { return 42; }
int notmain_func();

#endif

notmain.cpp

#include "notmain.hpp"

int notmain_func() {
    return shared_func();
}

Derleyin ve çalıştırın:

g++ -c -ggdb3  -O0 -Wall -Wextra -std=c++11 -pedantic-errors  -o 'notmain.o' 'notmain.cpp' 
g++ -c -ggdb3  -O0 -Wall -Wextra -std=c++11 -pedantic-errors  -o 'main.o' 'main.cpp' 
g++ -ggdb3  -O0 -Wall -Wextra -std=c++11 -pedantic-errors  -o 'main.out' notmain.o main.o
./main.out

Biz kaldırırsanız inlinegelen shared_func, bağlantı başarısız olur:

multiple definition of `shared_func()'

çünkü başlık birden çok .cppdosyaya dahil edilir .

Ama inlineile değiştirirsek constexpr, tekrar çalışır, çünkü constexpraynı zamanda ima eder inline.

GCC, ELF nesne dosyalarındaki sembolleri zayıf olarak işaretleyerek bunu uygular: Bir C ++ başlık dosyası, uygulamayı nasıl içerebilir?

GCC 8.3.0'da test edilmiştir.


3
BTW, bildirilen statik bir sınıf üyesi değişkeni constexprhala satır içi. cppreference.com : Belirtilen statik bir üye değişkeni (ancak bir ad alanı kapsam değişkeni değil) constexprörtük olarak bir satır içi değişkendir.
anton_rh

@anton_rh teşekkürler, bu kuralı görmedim, cevabı güncelle.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0386r0.pdf'in söylediği şey bu değil . constexpr'in değişkenler için satır içi ima ettiğini söylüyor. sınıf kapsamının ad alanı kapsamı arasında bir farktan söz edilmeden.
v.oddou
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.