2017-04-04 27 views
5

Bunu sıfırdan mümkün olmayan bir tür için çıplak kemiğe diyelim.C++ cinsinden bağımlı türler, sıfır olmayan tür

template<typename T> 
struct NonZero { 
    T val; 
}; 

Sorum o sıfırdan farklı olmadığını kontrol statik tip T bir edebi alıp etmek NonZero için bir kurucu yapmak mümkünse ve daha sonra val atar.

NonZero<int> n(0); // compilation error 
NonZero<int> n(1); // ok 

Yoksa sıfır olmayan bir türü arşivlemenin daha iyi bir yolu var mı?

+0

, belirli uygulamalar şablon uzmanlık sadece sağlanabilir ; İstenen nedir? – Codor

+0

Daha kolay bir yol olup olmadığını merak ediyordum, çünkü 'NonZero n (var)' da mümkün olmalıdır. – Sherushe

cevap

3

Başka bir seçenek için bir değer kontrol etmek olurdu constexpr yapıcıda sıfır olmak:

template<typename T> 
struct NonZero { 
    const T value; 
    constexpr NonZero(const T val) : 
     value(val != 0 ? val : throw std::runtime_error("should be non-zero")) 
    {} 
}; 

Kullanım:

NonZero<int> v(1);   // OK 
NonZero<int> v2(0);   // Compiles OK, but throws in run-time 
constexpr NonZero<int> v3(1); // OK 
constexpr NonZero<int> v4(0); // Compilation error 

Bu yöntem constexpr değişkenler için geçerlidir, ama çok daha basit görünüyor. Ayrıca, constexpr yapıcı ile struct yerine constexpr işlevini veya kullanıcı tanımlı bir değişkeni tam olarak aynı fikirle kullanabilirsiniz.

+0

Sadece gcc deyiminde bir hata alıyorum 'ifade' 'sabit bir ifade değil'. Problem hakkında bir fikrin var mı? – Sherushe

+2

Çok aptalım, yorumumu boşver, elbette değişken bir 0 ile oluşturulduğunda derleme hatası var. Yine de teşekkür ederim, tam da aradığım şey buydu. – Sherushe

+1

@Sherushe Rica ederim. Cevap vermek harika bir soruydu. – alexeykuzmin0

5

derleme zamanını bilindiğinden, bunu bir şablon tartışma yapmak ve kullanabilirsiniz std::enable_if:

template<typename T, T x> 
struct NonZero { 
    const static std::enable_if_t<x != T(0), T> value = x; 
}; 

Kullanımı:

int x = NonZero<int, 1>::value; // OK 
int x2 = NonZero<int, 0>::value;// Compilation error 
+0

Tipename T, Tx' ve 'x! = T (0)' tercih ederim. Bunun dışında, güzel ... – Aconcagua

+0

@Aconcagua İşaret ettiğin için teşekkürler, kodu güncelleyecektir – alexeykuzmin0

+0

Teşekkür ederim, bir Benim soruma biraz belirsiz. Bir lvalue int ile bir kurucu da gerekli bir şeydi. – Sherushe

1

Sadece bir argüman olarak değer alan bir kurucu sağlayacak başka bir yaklaşım düşünün. Temel fikir, yapıcıyı şablon haline getirmek ve değeri bir şablon argümanı olarak iletmektir. Ne yazık ki, basit bir şekilde bunu yapmak imkansız, ama biz this question bir çözümü kullanabilirsiniz:

template<typename T> 
struct NonZero { 
    const T value; 

    template<T x> 
    NonZero(std::integral_constant<std::enable_if_t<x != T(0), T>, x>) : value(x) { 
    } 
}; 

Kullanımı:

Anladığım kadarıyla
auto v = NonZero<int>(std::integral_constant<int, 1>()); // OK 
auto v2 = NonZero<int>(std::integral_constant<int, 0>()); // Compilation error 
İlgili konular