C ++ 11'de constexpr özelliğini ne zaman kullanmalısınız?


337

Bana öyle geliyor ki, "her zaman 5 döndüren bir işleve" sahip olmak, "bir işlevi çağırmak" anlamını bozmaktadır. Bu yeteneğin bir nedeni veya ihtiyacı olmalı ya da C ++ 11'de olmayacaktır. Neden orada?

// preprocessor.
#define MEANING_OF_LIFE 42

// constants:
const int MeaningOfLife = 42;

// constexpr-function:
constexpr int MeaningOfLife () { return 42; }

Bana öyle geliyor ki, gerçek bir değer döndüren bir işlev yazdıysam ve bir kod incelemesine geldiysem, birisi bana, dönüş 5 yazmak yerine sabit bir değer beyan etmeliyim diyebilirdi.


28
Bir döndüren özyinelemeli işlev tanımlayabilir misiniz constexpr? Eğer öyleyse, bir kullanım görebiliyorum.
ereOn

20
Sorunun "derleyici neden bir işlevin derleme zamanında değerlendirilip değerlendirilemeyeceğini kendisi belirleyebiliyorsa, yeni bir anahtar kelime (!) Tanıtmak" gerektiğini belirtmesi gerektiğine inanıyorum. "Bir anahtar kelime tarafından garantilenir" kulağa hoş geliyor ama bence bir anahtar kelimeye ihtiyaç duymadan mümkün olduğunda garanti almayı tercih ederim.
Kos

6
@Kos: C ++ dahili kullanıcılarıyla DAHA FAZLA muhatap olan biri muhtemelen sorunuzu tercih eder, ancak sorum daha önce C kodu yazmış, ancak C ++ 2011 anahtar kelimelerine aşina olmayan bir kişinin perspektifinden veya C ++ derleyici uygulama ayrıntılarından geliyor . Derleyici optimizasyonu ve sabit ifade-kesinti hakkında muhakeme yapabilmek, bundan daha ileri düzeyde bir kullanıcı sorusunun konusudur.
Warren P

8
@Kos Seninle aynı çizgileri düşünüyordum ve bulduğum cevap, constexpr olmadan , derleyicinin aslında sizin için zamanı derlediğini (kolayca) nasıl değerlendireceğini biliyor muydunuz ? Sanırım ne yaptığını görmek için montaj çıktısını kontrol edebilirsiniz, ancak derleyiciye bu optimizasyona ihtiyacınız olduğunu söylemek daha kolaydır ve eğer herhangi bir nedenle bunu sizin için yapamazsa, size güzel bir derleme verecektir. optimize etmek istediğiniz yerde sessizce optimizasyon yapmak yerine hata.
Jeremy Friesner

3
@Kos: Aynı şeyi söyleyebilirsin const. Aslında, zorunlu niyet olduğunu yararlıdır ! Dizi boyutları standart örnektir.
Orbit'te Hafiflik Yarışları

Yanıtlar:


303

Diyelim ki biraz daha karmaşık bir şey yapıyor.

constexpr int MeaningOfLife ( int a, int b ) { return a * b; }

const int meaningOfLife = MeaningOfLife( 6, 7 );

Artık iyi okunabilirliği korurken ve sadece bir sayıya sabit ayarlamaktan biraz daha karmaşık işlemlere izin verirken sabit olarak değerlendirilebilecek bir şey var.

Temel olarak, ne yaptığınızı daha belirgin hale getirdiği için sürdürülebilirliğe iyi bir yardım sağlar. Al max( a, b )örneğin:

template< typename Type > constexpr Type max( Type a, Type b ) { return a < b ? b : a; }

Orada oldukça basit bir seçim ama maxsabit değerlerle çağırırsanız derhal zamanında değil, çalışma zamanında hesaplandığı anlamına gelir .

Başka bir iyi örnek bir DegreesToRadiansişlev olabilir. Herkes derece okumayı radyanlardan daha kolay bulur. 180 derecenin radyan cinsinden olduğunu bilseniz de, aşağıdaki gibi çok daha net yazılmıştır:

const float oneeighty = DegreesToRadians( 180.0f );

Burada çok iyi bilgiler var:

http://en.cppreference.com/w/cpp/language/constexpr


18
Mükemmel nokta derleyiciye derleme zamanında değeri denemek ve hesaplamak için söyler. Belirli optimizasyonlar belirtildiğinde const neden bu işlevi sağlamıyor merak ediyorum? Yoksa öyle mi?
TamusJRoyce

11
@Tamus: Genellikle olur ama mecbur değildir. constexpr derleyiciyi zorunlu kılar ve yapamazsa bir hata verir.
Goz

20
Şimdi görüyorum. Günah (0.5) başka bir şeydir. Bu, C makrolarını düzgün bir şekilde değiştirir.
Warren P

10
Bunu yeni bir röportaj sorusu olarak görebilirim: const ve constexpr anahtar kelimesi arasındaki farkları açıklayın.
Warren P

2
Bu noktayı kendim için belgelemenin bir yolu olarak, "constexpr" yerine "const" işlevi ile yukarıdaki gibi benzer kod yazdım. Clang3.3, -pedantic-error ve -std = c ++ 11 kullandığım için ikincisinin derlenmesini beklemiyordum. "Constexpr" davasında olduğu gibi derlendi ve çalıştı. Bunun bir clang uzantısı olduğunu veya bu gönderinin yanıtlandığından beri C ++ 11 spesifikasyonunda bir değişiklik olduğunu düşünüyor musunuz?
Arbalest

144

Giriş

constexpruygulamaya bir şeyin sürekli ifade gerektiren bir bağlamda değerlendirilebileceğini söylemenin bir yolu olarak sunulmamıştır ; uygun uygulamalar C ++ 11'den önce bunu kanıtlayabilmiştir.

Bir uygulama ispat edemez şey değildir niyet kod belli parçasının:

  • Geliştiricinin bu varlıkla ifade etmek istediği şey nedir?
  • Kodun , işe yaradığı için sabit ifadede körü körüne kullanılmasına izin vermeli miyiz ?

Dünya onsuz ne olurdu constexpr?

Diyelim ki bir kütüphane geliştiriyorsunuz ve aralıktaki her tamsayı toplamını hesaplayabileceğinizi fark edelim (0,N].

int f (int n) {
  return n > 0 ? n + f (n-1) : n;
}

Niyet eksikliği

Bir derleyici, çeviri sırasında geçen argüman biliniyorsa yukarıdaki fonksiyonun sabit ifadede çağrılabilir olduğunu kolayca kanıtlayabilir ; ancak bunu bir niyet olarak ilan etmediniz - durum böyle oldu.

Şimdi başka biri gelir, fonksiyonunuzu okur, derleyici ile aynı analizi yapar; " Ah, bu işlev sabit bir ifadede kullanılabilir!" ve aşağıdaki kod parçasını yazar.

T arr[f(10)]; // freakin' magic

Optimizasyon

"Harika" bir kitaplık geliştiricisi olarak, fçağrıldığında sonucu önbelleğe almanız gerektiğine siz karar verirsiniz ; kim aynı değerleri tekrar tekrar hesaplamak ister ki?

int func (int n) { 
  static std::map<int, int> _cached;

  if (_cached.find (n) == _cached.end ()) 
    _cached[n] = n > 0 ? n + func (n-1) : n;

  return _cached[n];
}

Sonuç

Aptalca optimizasyonunuzu tanıtarak, sabit ifadenin gerekli olduğu bir bağlamda gerçekleşen işlevinizin her kullanımını kırdınız.

Fonksiyonun sabit bir ifadede kullanılabileceğine asla söz vermediniz ve constexprböyle bir vaat vermenin hiçbir yolu olmazdı.


Peki, neden ihtiyacımız var constexpr?

Constexpr'in birincil kullanımı niyet beyan etmektir .

Bir varlık olarak işaretlenmezse constexpr- asla sabit ifadede kullanılması amaçlanmamıştır ; ve öyle olsa bile, bu bağlamı teşhis etmek için derleyiciye güveniriz (çünkü niyetimizi göz ardı eder).


25
Bu muhtemelen doğru cevaptır, çünkü C ++ 14 ve C ++ 17'deki son değişiklikler constexprifadelerde çok daha geniş bir dil aralığının kullanılmasına izin verir . Başka bir deyişle, hemen hemen her şey açıklamalı edilebilir constexpr(? Belki bir gün bu sadece sırf bu ortadan kalkar), ve bir ne zaman kullanılacağını bir ölçüt olmadıkça constexprya da değil, hemen hemen tüm kod gibi yazılacak .
alecov

4
@alecov Kesinlikle her şey ... I/O, syscallve dynamic memory allocationkesinlikle olarak işaretlenir cann't constexpryanında, her şey gerektiği olmak constexpr.
JiaHao Xu

1
@alecov Bazı işlevlerin çalışma zamanında yürütülmesi amaçlanmıştır ve bunu derleme zamanında yapmak anlamsızdır.
JiaHao Xu

1
Ben de bu yanıtı en iyi şekilde beğeniyorum. Derleme zamanı değerlendirmesi düzgün bir optimizasyon, ancak gerçekten elde ettiğiniz constexprşey bir tür davranışın garantisidir. Tıpkı yaptığı gibi const.
Tomáš Zato - Monica

Hangi derleyici bu sınırsız sürümü int f (int n) { return n > 0 ? n + f (n-1) : n;} T arr[f(10)]; benim hiçbir yerde derleme elde edemez sağlar?
Jer

91

Al std::numeric_limits<T>::max(): hangi nedenle olursa olsun, bu bir yöntemdir. constexprburada yararlı olur.

Başka bir örnek: std::arraybaşka bir dizi kadar büyük bir C-dizisi (veya a ) bildirmek istiyorsunuz . Şu anda bunu yapmanın yolu şöyledir:

int x[10];
int y[sizeof x / sizeof x[0]];

Ancak yazabilmek daha iyi olmaz mıydı:

int y[size_of(x)];

Sayesinde constexprşunları yapabilirsiniz:

template <typename T, size_t N>
constexpr size_t size_of(T (&)[N]) {
    return N;
}

1
Güzel şablon kullanımı için +1, ancak constexpr olmadan tamamen aynı şekilde çalışır, değil mi?
Kos

21
@Kos: Hayır. Bir çalışma zamanı değeri döndürür. constexprkarşılaştırıcıyı işlevin bir derleme zamanı değeri döndürmesine zorlar (varsa).
deft_code

14
@Kos: constexprişlev çağrısı sonucunun bir derleme zamanı sabiti olup olmadığına bakılmaksızın, dizi boyutu bildiriminde veya şablon bağımsız değişkeni olarak kullanılamaz. Bu ikisi temelde sadece kullanım senaryolarıdır, constexprancak en azından use-case şablon argümanı biraz önemlidir.
Konrad Rudolph

2
"hangi nedenle olursa olsun, bu bir yöntemdir": Bunun nedeni, sadece C ++ 03'te derleme zamanı tamsayılarının olması, ancak başka bir derleme zamanı türü olmamasıdır, bu nedenle C ++ 11'den önceki rastgele türler için yalnızca bir yöntem çalışabilir.
Sebastian Mach

5
@LwCui Hayır, “ok” değil: GCC bazı şeyler için varsayılan olarak sadece gevşek. -pedanticSeçeneği kullanın ve hata olarak işaretlenecektir.
Konrad Rudolph

19

constexprfonksiyonları gerçekten güzel ve c ++ için büyük bir ektir. Ancak, çözdüğü sorunların çoğunun makrolarla yetersiz bir şekilde çözülebileceğinden haklısınız.

Bununla birlikte, kullanımlarından birinin constexprC ++ 03 eşdeğeri türünde sabitleri yoktur.

// This is bad for obvious reasons.
#define ONE 1;

// This works most of the time but isn't fully typed.
enum { TWO = 2 };

// This doesn't compile
enum { pi = 3.1415f };

// This is a file local lvalue masquerading as a global
// rvalue.  It works most of the time.  But May subtly break
// with static initialization order issues, eg pi = 0 for some files.
static const float pi = 3.1415f;

// This is a true constant rvalue
constexpr float pi = 3.1415f;

// Haven't you always wanted to do this?
// constexpr std::string awesome = "oh yeah!!!";
// UPDATE: sadly std::string lacks a constexpr ctor

struct A
{
   static const int four = 4;
   static const int five = 5;
   constexpr int six = 6;
};

int main()
{
   &A::four; // linker error
   &A::six; // compiler error

   // EXTREMELY subtle linker error
   int i = rand()? A::four: A::five;
   // It not safe use static const class variables with the ternary operator!
}

//Adding this to any cpp file would fix the linker error.
//int A::four;
//int A::six;

12
"ÇOK ince bir bağlantı hatası" açıklığa kavuşturabilir misiniz? Ya da en azından bir açıklamaya işaretçi mi?
enobayram

4
@enobayram, Üçlü operatör işlenenlerin adresini alır. Bu koddan belli değil. Her şey iyi derlenir, ancak adresi başarısız olmadığı için bağlantı başarısız olur four. static constDeğişkenimin adresini kimin aldığını anlamak için gerçekten kazmak zorunda kaldım .
deft_code

23
"Bu bariz sebeplerden dolayı kötü": en belirgin neden noktalı virgül olmak, değil mi?
TonyK

4
"Son derece ince linker hatası" beni tamamen şaşırttı. Ne kapsamda ne fourde fivekapsamda.
Steven Lu

3
ayrıca yeni enum classtüre bakın, bazı numaralandırma sorunlarını düzeltir.
ninMonkey

14

Okuduğum kadarıyla, constexpr ihtiyacı metaprogramlamadaki bir sorundan geliyor. Özellik sınıfları, işlevler olarak temsil edilen sabitlere sahip olabilir, düşünün: numeric_limits :: max (). Constexpr ile, bu tür işlevler meta programlamada veya dizi sınırları vb. Olarak kullanılabilir.

Başımın tepesinden başka bir örnek, sınıf arayüzleri için türetilmiş türlerin bazı işlemler için kendi sabitlerini tanımlamasını isteyebilirsiniz.

Düzenle:

SO'ya baktıktan sonra, başkaları bağlamlarla neyin mümkün olabileceğine dair bazı örnekler bulmuş gibi görünüyor.


"Bir arayüzün parçası olmak için bir işlev olmalısınız"?
Daniel Earwicker

Şimdi bunun yararlılığını görebildiğime göre, C ++ 0x hakkında biraz daha heyecanlıyım. İyi düşünülmüş bir şey gibi görünüyor. Olmaları gerektiğini biliyordum. Bu dil standardı uber-geeks nadiren rastgele şeyler yapar.
Warren P

Lambdas, iş parçacığı modeli, initializer_list, rvalue referansları, varyasyon şablonları, yeni bağlama aşırı yükleri hakkında çok daha heyecanlıyım ... dört gözle bekliyorum.
luke

1
Oh evet, ama zaten diğer bazı dillerde lambdas / kapanışları anlıyorum. constexprdaha güçlü bir derleme zamanı ifade değerlendirme sistemine sahip bir derleyicide daha kullanışlıdır. C ++ 'ın bu alanda gerçekten bir eşi yoktur. (bu C ++ 11, IMHO için güçlü bir övgü)
Warren P

11

Stroustrup'un "Going Native 2012" deki konuşmasından:

template<int M, int K, int S> struct Unit { // a unit in the MKS system
       enum { m=M, kg=K, s=S };
};

template<typename Unit> // a magnitude with a unit 
struct Value {
       double val;   // the magnitude 
       explicit Value(double d) : val(d) {} // construct a Value from a double 
};

using Speed = Value<Unit<1,0,-1>>;  // meters/second type
using Acceleration = Value<Unit<1,0,-2>>;  // meters/second/second type
using Second = Unit<0,0,1>;  // unit: sec
using Second2 = Unit<0,0,2>; // unit: second*second 

constexpr Value<Second> operator"" s(long double d)
   // a f-p literal suffixed by ‘s’
{
  return Value<Second> (d);  
}   

constexpr Value<Second2> operator"" s2(long double d)
  // a f-p literal  suffixed by ‘s2’ 
{
  return Value<Second2> (d); 
}

Speed sp1 = 100m/9.8s; // very fast for a human 
Speed sp2 = 100m/9.8s2; // error (m/s2 is acceleration)  
Speed sp3 = 100/9.8s; // error (speed is m/s and 100 has no unit) 
Acceleration acc = sp1/0.5s; // too fast for a human

2
Bu örnek Stroustrup'un Altyapı için Yazılım Geliştirme belgesinde de bulunabilir .
Matthieu Poullet

clang-3.3: hata: constexpr işlevinin dönüş türü 'Değer <İkinci>' değişmez bir tür değil
Mitja

Bu güzel ama değişmez kodu böyle koyan. İnteraktif bir hesap makinesi yazıyorsanız, derleyicinizin sizin için "birimlerinizi kontrol etmesini" sağlamak mantıklı olacaktır.
bobobobo

5
@bobobobo ya da Mars İklim Yörüngesi için navigasyon yazılımı yazıyorsanız, belki :)
Jeremy Friesner

1
Derlemek için - 1. Değişmez eklerde alt çizgi kullanın. 2. 100_m için "" _m operatörünü ekleyin. 3. 100.0_m kullanın veya uzun süre imzasız kabul eden bir aşırı yük ekleyin. 4. Değer yapıcı constexpr. 5. İlgili işleci / Value sınıfına şu şekilde ekleyin: constexpr auto operator / (const Value <Y> ve diğer) const {return Value <Unit <TheUnit :: m - Value <Y> :: TheUnit :: m, TheUnit :: kg - Değer <Y> :: TheUnit :: kg, TheUnit :: s - Değer <Y> :: TheUnit :: s >> (val / other.val); }. Burada TheUnit, Value sınıfının içine eklenen Unit için typedef'tir.
0kcats

8

Başka bir kullanım (henüz belirtilmemiş) constexprkuruculardır. Bu, çalışma zamanı sırasında başlatılması gerekmeyen derleme zamanı sabitleri oluşturulmasına izin verir.

const std::complex<double> meaning_of_imagination(0, 42); 

Bunu kullanıcı tanımlı değişmez değerlerle eşleştirdiğinizde değişmez kullanıcı tanımlı sınıflar için tam desteğiniz olur.

3.14D + 42_i;

6

Eskiden meta programlı bir model vardı:

template<unsigned T>
struct Fact {
    enum Enum {
        VALUE = Fact<T-1>*T;
    };
};

template<>
struct Fact<1u> {
    enum Enum {
        VALUE = 1;
    };
};

// Fact<10>::VALUE is known be a compile-time constant

Bu constexprtür yapıları şablonlara ve uzmanlık, SFINAE ve diğer şeylere sahip garip yapılara gerek kalmadan yazmanıza izin verildiğine inanıyorum - ancak tam olarak bir çalışma zamanı işlevi yazacağınız gibi, ancak sonucun derlenecek şekilde belirleneceği garantisiyle -zaman.

Ancak aşağıdakilere dikkat edin:

int fact(unsigned n) {
    if (n==1) return 1;
    return fact(n-1)*n;
}

int main() {
    return fact(10);
}

Bunu derleyin g++ -O3ve göreceksinizfact(10) derleme zamanında gerçekten değerlendirildiğini !

VLA uyumlu bir derleyici (C99 modunda bir C derleyicisi veya C99 uzantılarına sahip C ++ derleyicisi) şunları yapmanıza bile izin verebilir:

int main() {
    int tab[fact(10)];
    int tab2[std::max(20,30)];
}

Ama şu anda standart olmayan C ++ - constexprbununla mücadele etmenin bir yolu gibi görünüyor (VLA olmadan bile, yukarıdaki durumda). Ve hala şablon argümanları olarak "resmi" sabit ifadelere sahip olma ihtiyacı sorunu var.


Olgu fonksiyonu derleme zamanında değerlendirilmez. Bunun constexpr olması ve sadece bir dönüş ifadesi olması gerekir.
Sumant

1
@Sumant: Derleme zamanında değerlendirilmesi gerekmediği konusunda haklısınız, ama öyle! Derleyicilerde gerçekte neler olduğuna değiniyordum. Son GCC'de derleyin, ortaya çıkan soruyu görün ve bana inanmıyorsanız kendiniz kontrol edin!
Kos

Eklemeye çalışın std::array<int, fact(2)>ve () öğesinin derleme zamanında değerlendirilmediğini göreceksiniz. Sadece GCC optimizatörü iyi bir iş çıkarıyor.

1
Ben de öyle dedim ... Gerçekten bu kadar belirsiz miyim? Son paragrafa bakınız
Kos

5

Bir projeyi c ++ 11'e geçirmeye başladınız ve aynı işlemi gerçekleştirmenin alternatif yöntemlerini temizleyen constexpr için mükemmel bir durumla karşılaştınız. Buradaki kilit nokta, fonksiyonu yalnızca constexpr olarak tanımlandığında dizi boyutu bildirimine yerleştirebilmenizdir. Bunun içinde bulunduğum kod alanı ile ilerlerken çok yararlı olduğunu görebildiğim bir dizi durum var.

constexpr size_t GetMaxIPV4StringLength()
{
    return ( sizeof( "255.255.255.255" ) );
}

void SomeIPFunction()
{
    char szIPAddress[ GetMaxIPV4StringLength() ];
    SomeIPGetFunction( szIPAddress );
}

4
Bu aynı şekilde yazılabilir: const size_t MaxIPV4StringLength = sizeof ("255.255.255.255");
Superfly Jon

static inline constexpr const automuhtemelen daha iyidir.
JiaHao Xu

3

Diğer tüm cevaplar harika, sadece şaşırtıcı olan constexpr ile yapabileceğiniz bir şeyin harika bir örneğini vermek istiyorum. Phit'e bakınız ( https://github.com/rep-movsd/see-phit/blob/master/seephit.h ) derleme zamanı HTML ayrıştırıcısı ve şablon motorudur. Bu, HTML'yi işleyebileceğiniz ve işlenebilen bir ağaçtan çıkabileceğiniz anlamına gelir. Ayrıştırma işleminin derleme zamanında yapılması, size ekstra performans sağlayabilir.

Github sayfası örneğinden:

#include <iostream>
#include "seephit.h"
using namespace std;



int main()
{
  constexpr auto parser =
    R"*(
    <span >
    <p  color="red" height='10' >{{name}} is a {{profession}} in {{city}}</p  >
    </span>
    )*"_html;

  spt::tree spt_tree(parser);

  spt::template_dict dct;
  dct["name"] = "Mary";
  dct["profession"] = "doctor";
  dct["city"] = "London";

  spt_tree.root.render(cerr, dct);
  cerr << endl;

  dct["city"] = "New York";
  dct["name"] = "John";
  dct["profession"] = "janitor";

  spt_tree.root.render(cerr, dct);
  cerr << endl;
}

1

Temel örneğiniz, sabitlerin kendileriyle aynı argümana hizmet ediyor. Neden kullanmalı

static const int x = 5;
int arr[x];

bitmiş

int arr[5];

Çünkü çok daha bakımlı. Constexpr kullanmak, yazmak ve okumak için mevcut meta programlama tekniklerinden çok, çok daha hızlıdır.


0

Bazı yeni optimizasyonlar sağlayabilir. constgeleneksel olarak tip sistemi için bir ipucudur ve optimizasyon için kullanılamaz (örneğin bir constüye işlevi const_castnesneyi yasal olarak değiştirebilir ve bu nedenle constoptimizasyon için güvenilir olamaz).

constexprişleve girişlerin sabit olması koşuluyla ifadenin gerçekten sabit olduğu anlamına gelir . Düşünmek:

class MyInterface {
public:
    int GetNumber() const = 0;
};

Bu, başka bir modülde ortaya çıkarsa, derleyici GetNumber()her çağrıldığında farklı değerler döndürmeyeceğine güvenemez - hatta aralarında sabit olmayan çağrılar olmadan bile - constuygulamada atılabilirdi. (Açıkçası bunu yapan herhangi bir programcı vurulmalıdır, ancak dil buna izin verir, bu nedenle derleyici kurallara uymalıdır.)

Ekleme constexpr:

class MyInterface {
public:
    constexpr int GetNumber() const = 0;
};

Derleyici artık dönüş değerinin GetNumber()önbelleğe alındığı bir optimizasyon uygulayabilir ve ek çağrıları ortadan kaldırır GetNumber(), çünkü constexprdönüş değerinin değişmeyeceğine dair daha güçlü bir garantidir.


Aslında const olabilir optimizasyon kullanılacak ... Bir değeri değiştirmek için tanımsız davranıştır const tanımlı bile sonra const_castIIRC. constÜye işlevleri için tutarlı olmasını beklerdim , ancak bunu standartla kontrol etmem gerekir. Bu derleyicinin orada güvenle optimizasyon yapabileceği anlamına gelir.
Kos

1
@Warren: optimizasyonun gerçekten yapılıp yapılmadığı önemli değil, sadece izin veriliyor. @Kos: bu takdirde bir az bilinen incelik bu özgün bir amacı edilmiş olup const (bildirilen int xVS. const int x), o zaman bunu değiştirmek için güvenli const_castbir işaretçi / referansı const uzak ing. Aksi takdirde, const_casther zaman tanımsız davranışları çağırır ve işe yaramaz :) Bu durumda, derleyicinin orijinal nesnenin sabitliği hakkında hiçbir bilgisi yoktur, bu yüzden söyleyemez.
AshleysBrain

@Kos Ben const_cast burada tek sorun olduğunu sanmıyorum. Const yönteminin genel bir değişkeni okumasına ve hatta değiştirmesine izin verilir. Tersine, başka bir evreden biri de çağrılar arasındaki sabit nesneyi değiştirebilir.
enobayram

1
"= 0" burada geçerli değil ve kaldırılması gerekiyor. Bunu kendim yaparım, ama bunun SO protokolüne uygun olduğundan emin değilim.
15

Her iki örnek de geçersiz: first (( int GetNumber() const = 0;) GetNumber()yöntemi sanal olarak bildirmelidir . İkinci ( constexpr int GetNumber() const = 0;) geçerli değildir, çünkü saf belirteç ( = 0) yöntemin sanal olduğunu ima eder, ancak constexpr'ler sanal olmamalıdır (ref: en.cppreference.com/w/cpp/language/constexpr )
stj

-1

Ne zaman kullanılır constexpr:

  1. ne zaman bir derleme zaman sabiti varsa.

Size katılıyorum, ancak bu cevap neden constexpr önişlemci makrolarına göre tercih edilmesi gerektiğini açıklamıyor const.
Sneftel

-3

Gibi bir şey için yararlı

// constants:
const int MeaningOfLife = 42;

// constexpr-function:
constexpr int MeaningOfLife () { return 42; }

int some_arr[MeaningOfLife()];

Bunu bir özellik sınıfı veya benzeri ile bağlayın ve oldukça kullanışlı hale gelir.


4
Örneğinizde, düz bir sabite göre sıfır avantaj sunar, bu yüzden soruyu gerçekten cevaplamaz.
jalf

Bu anlaşılmaz bir örnektir, AnlamıOfLife () değerinin başka bir yerden alınıp alınmadığını düşünün, başka bir işlev veya #define veya seri therof deyin. Ne döndürdüğünü bilmiyor olabilirsiniz, kütüphane kodu olabilir. Diğer örnekler, constexpr size () yöntemine sahip değişmez bir kap düşünün. Artık int arr [container.size ()];
plivesey

2
@plivesey lütfen daha iyi bir örnekle cevabınızı düzenleyebilirsiniz.
Mukesh
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.