2017-07-07 25 views
8

std::is_integral'a bağlı olarak yalnızca birkaç türü kabul eden birkaç işlev nesnesine sahip bir kitaplığım var. Koşul başarısız olduğunda dönmek için std::is_invocable istiyorum, ancak bir kullanıcı işlev nesnesinin bir örneğini çağırmaya çalıştığında ben de güzel bir hata iletisi istiyorum. İşte fonksiyon nesnelerin basitleştirilmiş bir örnektir Şu anda var:static_assert ve std :: is_invocable öğesinin en iyisine sahip olmak

böyle bir uygulamayla
struct function 
{ 
    template<typename Iterator> 
    auto operator()(Iterator first, Iterator last) const 
     -> std::enable_if_t<std::is_integral_v< 
      typename std::iterator_traits<Iterator>::value_type 
     >> 
    { /* something */ } 
}; 

, std::is_invocable SFINAE koşul karşılanmadığında beklendiği gibi std::false_type olmakla birlikte, arama çalıştığınızda kullanıcıların çirkin SFINAE hata mesajlarıyla karşılaşabilirsiniz işlev nesnesi, SFINAE koşulunu karşılamayan parametrelerle.

Bu uygulamayla
struct function 
{ 
    template<typename Iterator> 
    auto operator()(Iterator first, Iterator last) const 
     -> void 
    { 
     static_assert(std::is_integral_v<typename std::iterator_traits<Iterator>::value_type>, 
         "function can only be called with a collection of integers"); 

     /* something */ 
    } 
}; 

, kullanıcılar özgün SFINAE koşulları sağlamadığını dostu hata iletileri almak, ancak olmadığını sorulduğunda std::is_invocablestd::true_type geçerli:

daha iyi hata iletileri almak için, bunun yerine aşağıdaki çözümü çalıştı function örneği, std::is_integral ürününü karşılamayan bir tür işleyebilir.

Ben decltype(auto), if constexpr ve diğer mekanizmaları kapsayan çeşitli hile ve varyasyonlar denedi, ancak hata iletileri güzel bir sınıf alamadım ve std::is_invocable beklenen std::false_type karşılık nereye function yanlış türleri ile çağırılacak olup isterken.

Burada nelerin eksik? Doğru std::is_invocableve kullanıcı dostu hata iletileri almanın bir yolu var mı?

+0

Kısa bir süre önce bu konuyla ilgili bir blog yazısı yazdım: https://gracicot.github.io/tricks/2017/07/01/deleted-function-diagnostic.html –

cevap

7

İşte korkunç bir yol. Bir aşırı ekleyin: contrained fonksiyon şablonu daha uzmanlaşmış ve tercih edilir çünkü

template <typename Iterator> 
auto operator()(Iterator first, Iterator last) const 
    -> std::enable_if_t<std::is_integral_v< 
     typename std::iterator_traits<Iterator>::value_type 
    >>; 

template <typename Iterator, class... Args> 
void operator()(Iterator, Iterator, Args&&...) const = delete; // must be integral 

Bu, is_invocable<> koşulu karşılar - koşul karşılandığında yani eğer, fonksiyon silinmeden başka invocable olduğunu.

Bu onu aramak denerseniz olsun beri, biraz daha iyi hata durumda yapar:

foo.cxx: In function ‘int main()’: 
foo.cxx:31:13: error: use of deleted function ‘void function::operator()(Iterator, Iterator, Args&& ...) const [with Iterator = std::__cxx11::basic_string<char>*; Args = {}]’ 
    f(&i, &i); 
      ^
foo.cxx:19:10: note: declared here 
    void operator()(Iterator, Iterator, Args&&...) const = delete; // must be integral 
      ^~~~~~~~ 

comment statik assert gibi çeşit olan hata mesajı içinde görünür mesaj?


Bu aslında Kavramlar için motivasyonlardan biridir. Bir requires yerine bir enable_if ile elde ederiz:

var
foo.cxx: In function ‘int main()’: 
foo.cxx:26:13: error: no match for call to ‘(function) (std::__cxx11::string*, std::__cxx11::string*)’ 
    f(&i, &i); 
      ^
foo.cxx:11:10: note: candidate: void function::operator()(Iterator, Iterator) const requires is_integral_v<typename std::iterator_traits<_Iter>::value_type> [with Iterator = std::__cxx11::basic_string<char>*] 
    void operator()(Iterator first, Iterator last) const 
      ^~~~~~~~ 
foo.cxx:11:10: note: constraints not satisfied 
foo.cxx:11:10: note: ‘is_integral_v<typename std::iterator_traits<_Iter>::value_type>’ evaluated to false 

... biraz daha iyi sanırım.

+0

Çözümlerin çözümleri gerçekten biraz daha iyi. SFINAE davranışına ihtiyaç duyduğumda başka yerler var, benim durumumda '= delete'ın geçerli olup olmadığını kontrol etmem gerekiyordu, ama bu keşif için ilginç bir yol olabilir. – Morwenn

+4

[= Makale] hünerlerini geliştiren [bir makale] (https://gracicot.github.io/tricks/2017/07/01/deleted-function-diagnostic.html) 'yi adanmış bir '' 'sağlayan static_assert' mesajı, bu da kötü değil. – Morwenn

+0

@Morwenn Yazının yazarının doğru olup olmadığını merak ediyorum ... Seni okudum ** herhangi bir geçerli uzmanlığa sahip olmayan şablon oluşturamıyorum ve static_assert (! Std :: is_same_v , "message") 'olurdu Bu kuralı çiğneyerek kodun bile teşhis edilmeden hatalı biçimlendirilmesini sağlayın. –

İlgili konular