2016-08-26 34 views
8

Bu, Detecting constexpr with SFINAE numaralı soruya verilen bir sorudur.SFINAE constexpr ile std :: get

Bir tuple öğesinin (veya std::get ile kullanılabilecek bir şeyin) Constexpr olup olmadığını belirlemek istiyorum.

template<size_t> struct sfinae_true : std::true_type{}; 

template<size_t N, class T> 
auto check(const T& arg) -> sfinae_true<(std::get<N>(arg),N)>; 

template<size_t N, class> 
std::false_type check(...); 

Şimdi benim test sürücüsü kodu:

int main() 
{ 
    constexpr std::tuple<size_t, size_t> arg(4,5); 
    typedef decltype(check<0,decltype(arg)>(arg)) is_cexpr; 
    std::cout << "is constexpr? " << is_cexpr::value << '\n'; 
} 

Ancak bu her zaman dışarı yazdırır benim için false yüzden Xeo verdi ne benzer aşağıdaki yardımcıları yazdı! Yanlış aşırı yük her zaman denir değil nedense, ben yanlış aşırı dışarı yorumladı olmadığını kontrol edin ve derleyici hatası almak için: Ancak

note: candidate template ignored: substitution failure [with N = 0, T = const std ::tuple]: non-type template argument is not a constant expression
auto check(const T& arg) -> sfinae_true<(std::get(arg),0)>;

, ben std::get<N>(arg) çağırabilir biliyoruz ve bir constexpr değerini alırım :

template<size_t N> 
class A{}; 

int main() 
{ 
    constexpr std::tuple<size_t, size_t> arg(4,5); 
    A<std::get<0>(arg)> a_val; 
} 

Bu, yalnızca iyi derler.

  • Neden denetim işlevi karmaşıklığı doğru şekilde algılamıyor?
  • Bunu nasıl düzeltirim?

Bunu Ubuntu 16.04 üzerinde Clang 3.8.0 ile test ettim.

düzenleme: Bu tamamen virgül operatörünün kurtulur

template<size_t N, class T> 
auto check(const T& arg) 
{ 
    return sfinae_true<(std::get<N>(arg)*0)>(); 
} 

, GCC 5.4.0 gayet derler: Sam'in Yanıta göre bir başka testte, ben formu çalıştı

ama Clang 3.8.0 hala hakkında şikayet ediyor. İlginç bir şekilde, Clang, arg'un kendisinin constexpr olmadığını vurgular.

Bu sorun neden hala devam ediyor? Constexpr işlev argümanları için kurallar nelerdir?

+2

Sorun şu ki 'arg' parametresi' constexpr' değil… – Jarod42

+1

(Ben Jarod42'nin ne anlama geldiğini biraz daha genişletmek için: 'arg' bir fonksiyon parametresidir Fonksiyona sağladığınız argüman sabit bir ifade olsa bile, asla sabit bir ifade olarak düşünülmez.) – dyp

+0

Bu yöntem işe yaramıyorsa işlev çağrısının sonucunun constexpr olup olmadığını nasıl anlarım? Açıkçası, 'a_val' nesnesini inşa ederek tuple'ı bir constexpr değeri olarak kullanabilirim. – helloworld922

cevap

3

Bu bir derleyici sorunu gibi görünüyor.

t.C:8:61: error: template argument 1 is invalid auto check(const T& arg) -> sfinae_true<(std::get(arg),N)>;

Ama biraz bu verdiği sonra ben gcc 6.1.1 ile beklenen sonuçları elde:

#include <tuple> 
#include <type_traits> 
#include <iostream> 

template<size_t> struct sfinae_true : std::true_type{}; 

template<size_t N, class T> 
auto check(const T& arg) 
{ 
    return sfinae_true<(std::get<N>(arg),N)>(); 
} 

template<size_t N, class> 
std::false_type check(...); 

int main() 
{ 
    constexpr std::tuple<size_t, size_t> arg(4,5); 
    typedef decltype(check<0,decltype(arg)>(arg)) is_cexpr; 
    std::cout << "is constexpr? " << is_cexpr::value << '\n'; 
} 

Bu sonuçlanır:

template<size_t N, class T> 
auto check(const T& arg) -> sfinae_true<(std::get<N>(arg),N)>; 

gcc bu derlenmeyecektir

is constexpr? 1 

Virgüllerin olmadığını unutmayın. C++ öncesi sabit ifadelere izin verilir. O zamandan kalan bir şey olabilir ...

+0

Senin tweak 3.8.0 clang denedim ve işe yaramaz, ama GCC 5.4.0 ile yapar. İlginç bir şekilde, argoda non-constexpr olarak vurgulanan kısım, virgül operatör değil, arg argümanı değil (ben bunu virgül operatörünü kaldırarak test ettim). – helloworld922

+0

Zorunlu davranış, sürümünüzde farklıdır. SFINAE, çıkarılan getiri türleri için geçerli değildir; SFINAE hemen bağlam içinde iken, getiri türü kesintisi, fonksiyon şablonunun oldukça derin bir örneğini gerektirir. – dyp

+0

İlginçtir, @dyp, sonuçta istenen sonuçtur. Constexpr olmayan bir parametre bir derleme hatasıyla sonuçlanmadı, ancak beklenen varsayılan şablon. Şablon fonksiyonunun beyan türünün beyan zamanında bildirilmiş hali gibi görünüyor ve daha sonra normalde SFINAE çözünürlüğüne katılıyor. –