Bir constexpr içinde std :: string kullanmak mümkün mü?


176

C ++ 11, Ubuntu 14.04, GCC varsayılan araç zinciri kullanılarak .

Bu kod başarısız:

constexpr std::string constString = "constString";

hata: 'constString' constexpr değişkeninin 'const dizesi {aka const std :: basic_string}' harfi değişmez ... çünkü ... 'std :: basic_string' önemsiz olmayan bir yıkıcıya sahip

Kullanmak mümkün mü std::stringbir de constexpr? (görünüşe göre değil ...) Öyleyse, nasıl? A karakter dizgisini kullanmanın alternatif bir yolu var mı constexpr?


2
std::stringgerçek bir tür değil
Piotr Skotnicki

7
@PiotrS - soru diyor ki ...
Vektör

4
@Vector size constexpr'in ne için olduğunu sordum ya da neden std::stringconstexpr olmak istiyorsunuz? SO üzerinde birkaç derleme zamanı dize uygulaması vardır. Hata mesajını anlar ve yalnızca değişmez türlerin constexpr yapılabileceğini biliyorsanız, değişmez bir tür constexpr yapıp yapamayacağınızı sormanın anlamı nedir? bir kişinin bir bağlam örneği olmasını isteyebilmesinin birkaç nedeni olabilir, bu yüzden sorunuzu netleştirmenizi öneririm
Piotr Skotnicki

2
@PiotrS olarak evet. dedi, orada constexprdize uygulamaları var. std::stringonlardan biri değil.
tenfour

3
@PiotrS - SO üzerinde birçok derleme zamanı dize uygulamaları var - Tamam, teşekkürler, anlaşıldı. Bu benim için bir seçenek değil ama sorumu cevaplıyor: hiçbir şekilde std :: string çalışacak. Tenfour'a bahsettiğim gibi, std :: string'i işe yarayacak şekilde kullanmanın bir yolu olup olmadığını merak ediyordum. Kesinlikle farkında olmadığım birçok püf noktası var.
vektör

Yanıtlar:


168

Hayır, derleyiciniz size kapsamlı bir açıklama yaptı.

Ama bunu yapabilirsiniz:

constexpr char constString[] = "constString";

Çalışma zamanında, bu std::stringgerektiğinde bir zaman oluşturmak için kullanılabilir .


78
Neden olmasın constexpr auto constString = "constString";? Bu çirkin dizi sözdizimini kullanmaya gerek yok ;-)
stefan

81
Bu soru bağlamında daha açıktır. Demek istediğim, hangi dize türlerinden seçim yapabileceğinizle ilgili. Kullanacağım veri türünü vurgulamaya çalıştığımdan char[]daha ayrıntılı / net auto.
tenfour

7
@tenfour Doğru, bu iyi bir nokta. Sanırım bazen biraz fazla auto;-) kullanmaya odaklandım
stefan

1
Ancak 17 c ++ ile hiçbir @FelixDombek kullanabilirdin constexpr auto s = "c"sv;getirilmesi nedeniylestring_view
wich

6
Bu bağlamda bir char dizisini bağlamlamak mantıklı mı? Bir dize oluşturmak için kullanırsanız, yine de kopyalanacaktır. Kelimenin tam anlamını dizenin yapıcısına geçirme ve böyle bir constexpr dizisini geçirme arasındaki fark nedir?
KjMag

169

İtibariyle 20 C ++ , evet.

İtibariyle C ++ 17 , şunları kullanabilirsiniz string_view:

constexpr std::string_view sv = "hello, world";

A string_view, herhangi bir stringnesne dizisine değişmez, sahip olmayan bir referans olarak hareket eden benzer bir charnesnedir.


6
Bu sabiti her geçtiğinizde const std::string&yeni bir std :: string alan bir fonksiyona geçmeniz gerektiğini unutmayın. Bu, bir sabit oluştururken genellikle aklında olanın tam tersidir. Bu nedenle, bunun iyi bir fikir olmadığını söyleme eğilimindeyim. En azından dikkatli olmalısın.
Rambo Ramon

29
@RamboRamon string_viewdolaylı olarak dönüştürülemez string, bu yüzden bir stringa string_view. Tersine, char const* bir örtük olarak dönüştürülebilir stringböylece kullanarak, string_viewbu anlamda aslında daha güvenlidir.
Joseph Thomson

4
Açıklama için teşekkürler. Tamamen katılıyorum ve gerçekten string_viewde bunun dolaylı olarak dönüştürülemediğini unuttum string. IMO getirdiğim sorun hala geçerli, ancak string_viewözellikle geçerli değil . Aslında, belirttiğiniz gibi, bu konuda daha da güvenlidir.
Rambo Ramon

5
Bu cevabın string_viewsadece bir bağlantı yerine ne olduğu hakkında daha fazla şey söylemesi harika olurdu .
eric

23

C ++ 20, constexprdizeler ve vektörler ekleyecektir

Aşağıdaki teklif açıkça kabul edildi : http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0980r0.pdf ve aşağıdaki gibi yapıcıları ekler:

// 20.3.2.2, construct/copy/destroy
constexpr
basic_string() noexcept(noexcept(Allocator())) : basic_string(Allocator()) { }
constexpr
explicit basic_string(const Allocator& a) noexcept;
constexpr
basic_string(const basic_string& str);
constexpr
basic_string(basic_string&& str) noexcept;

tüm / çoğu yöntemin constexpr sürümlerine ek olarak.

GCC 9.1.0'dan itibaren destek yoktur, aşağıdakiler derlenemez:

#include <string>

int main() {
    constexpr std::string s("abc");
}

ile:

g++-9 -std=c++2a main.cpp

hatalı:

error: the type const string {aka const std::__cxx11::basic_string<char>’} of constexpr variable s is not literal

std::vectortartışıldığı yer: constexpr std :: vector oluşturulamıyor

Ubuntu 19.04'te test edildi.


19

Sorun önemsiz yıkıcı olmadığından yıkıcı kaldırılırsa , bu tür std::stringbir constexprörnek tanımlamak mümkündür . Bunun gibi

struct constexpr_str {
    char const* str;
    std::size_t size;

    // can only construct from a char[] literal
    template <std::size_t N>
    constexpr constexpr_str(char const (&s)[N])
        : str(s)
        , size(N - 1) // not count the trailing nul
    {}
};

int main()
{
    constexpr constexpr_str s("constString");

    // its .size is a constexpr
    std::array<int, s.size> a;
    return 0;
}

18
Bu c ++ 17 temelde ne string_viewolması dışında olan string_viewişlevi çoğu verir dan bildiğine görestd::string
wich
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.