2012-10-23 22 views
15

Normal olarak, constexpr'in herhangi bir yan etkisi olmamalıdır. Bununla birlikte, atılan istisnaların yapıcılarında yan etkilerin kullanılmasının mümkün olduğunu keşfettim. Bu teknik, aşağıdaki programda gösterildiği gibi, constexpr işlevleri için assert() öykünmesi için kullanılabilir.Constexpr tarafından atılan istisnalarda yan etkileri kullanmak yasal mıdır?

#include <iostream> 
#include <cstdlib> 
#include <stdexcept> 

struct constexpr_precond_violated : std::logic_error 
{ 
    constexpr_precond_violated(const char* msg) : 
    std::logic_error(msg) 
    { 
    std::cerr << msg << '\n'; 
    abort(); // to get a core dump 
    } 
}; 

#define TO_STRING_IMPL(x) #x 
#define TO_STRING(x) TO_STRING_IMPL(x) 

#define CONSTEXPR_PRECOND(cond, value) \ 
    ((!(cond)) ? throw constexpr_precond_violated(\ 
    "assertion: <" #cond "> failed (file: " \ 
    __FILE__ ", line: " TO_STRING(__LINE__) ")") \ 
    : (value)) 

constexpr int divide(int x, int y) 
{ 
    return CONSTEXPR_PRECOND(y != 0, x/y); 
} 

int main(int argc, char** argv) 
{ 
    // The compiler cannot know argc, so it must be evaluated at runtime. 
    // If argc is 2, the precondition is violated. 
    return divide(100, argc - 2); 
} 

G ++ 4.7.2 ve clang ++ 3.1 ile test ettim. Ön koşullar başarısız olduğunda, hata konumunu ve bir çekirdek dökümünü alırsınız.

./constexpr_assert some_arg 
assertion: <y != 0> failed (file: constexpr_assert.cpp, line: 26) 
Aborted (core dumped) 

Geçerli derleyicilerle çalışıyor, ancak yasal C++ 11 mi?

+1

Out divide() 'işlevinin 2. argümanı olarak" 0 "derleme zamanı sabiti sağladığınızda ne olur? * Derleyici * "bir istisna atar" mı? :) –

+0

static_assert (böl (1, 0)> = 0, "test"); sadece geri dönüşünü derleyemez (1, 0); Clang ile derler ve yalnızca çalışma zamanında başarısız olur. –

+3

Sabit ifadeler ile 'constexpr' işlevi arasında ayrım yapmak için dikkatli olmalısınız. "Constexpr 'gibi yan etkilerden arınmış olmalı" bir şey kesin değildir. "Constexpr" kelimesini bir anahtar kelime olarak düşünmeyin (“statik” akla gelir). –

cevap

14

Yasaldır. Her constexpr işlevi için

orada sabit bir ekspresyon (§7.1.5/5) neden bazı bağımsız değişken değerler olmalıdır: herhangi bir işlev bağımsız değişken değerleri şekilde varsa, bir constexpr fonksiyon için

işlev çağırma ikamesi sabit bir ifade (5.19) üretecektir, program kötü biçimlendirilmiş; tanı gerekli değil. Bu her olası bağımsız değişken değeri sabit bir ifadede ürünü olması gerektiğini anlamına gelmez

Not. divide, açıkça bir ifade ile sonuçlanan bazı bağımsız değişken değerlerine sahiptir: divide(1, 1) basit bir örnektir. Yani, tanım açıkça geçerlidir.

Ancak divide(1, 0) çağrılabilir mi? Evet yapabilir. eşdeğer olmayan constexpr için

bir constexpr işlevine bir çağrı araması olarak aynı sonucu verir: Bir constexpr fonksiyonu veya "normal" bir fonksiyonu (§7.1.5/7) yürütmesini arasında hemen hemen hiç fark yoktur işlevinin constexpr işlevine çağrılması dışında her açıdan işlev, sabit bir ifadede görünebilir. sabit ifadelerde görünebilir constexpr işlevlerine çağırır, ama hiçbir şey sabit ifadelerde sonuçlanmayan onları yasaklayan

Not. Bu, hem derleme zamanı hem de çalışma zamanı argümanlarıyla birlikte constexpr işlevlerini çağırabilecek şekilde tasarlanmıştır (aksi takdirde constexpr'un kullanışlılığı sınırlı bir şekilde sınırlı olacaktır). Bu bir şekilde aşağıdakilerden biri içermediği sürece

bir koşullu ekspresyonu bir çekirdek sabit ifade olup: bütünlüğü için

, en sabit bir ifade (§5.19/2) kılan bakalım Potansiyel olarak değerlendirilen alt ekspresyon (§3.2), ancak değerlendirilmemiş olan mantıksal AND (§5.14), mantıksal OR (§5.15), ve koşullu (§5.16) işlemlerin alt ifadeleri [...] dikkate alınmamış değildir.

Yani, divide(1, 1) sabit bir ifadedir, ancak divide(1, 0) değildir.Bir şablon parametresinde divide(1, 0) kullandıysanız, program kötü biçimlendirilmiş olacaktır. Ama aksi takdirde iyidir.

İlgili konular