2016-08-17 11 views
6

Używam prostego SFINAE podstęp, by sprawdzić, czy funkcja członek nie istnieje, tak jak poniżej:Clang narzeka niezdefiniowanej funkcji constexpr w unevaluated kontekście

#include <type_traits> 

template <typename C> 
struct has_size { 
    template <typename T> 
    static constexpr auto check(T*) -> 
     decltype(std::declval<T const>().size(), std::true_type{}); 

    template <typename> 
    static constexpr auto check(...) -> std::false_type; 

    static constexpr bool value = decltype(check<C>(nullptr))::value; 
}; 

// Usage: 
static_assert(has_size<std::vector<int>>::value, "std::vector<int> has size()"); 

(Jestem świadomy, że there’s a simpler method teraz, ale nie był” t kiedy napisałem ten fragment kodu.)

Ten kod działa na GCC. jednak dzyń emituje ostrzeżenie (wszystkie wersje górę do Apple LLVM 7.3, w zależności od tego, który jest w górę):

decltype.cpp:15:27: error: inline function 'has_size<std::__1::vector<int, std::__1::allocator<int> > >::check<std::__1::vector<int, std::__1::allocator<int> > >' is not defined [-Werror,-Wundefined-inline] 
    static constexpr auto check(T*) -> 
        ^
decltype.cpp:22:44: note: used here 
    static constexpr bool value = decltype(check<C>(nullptr))::value; 

Innymi słowy, dzyń oczekuje, że funkcje, które zostaną określone, nie tylko ogłosił, mimo że są one nigdy nie nazywane (tylko w nieocenionym kontekście decltype).

Czy to błąd w klangu? Czy też słuszne jest narzekanie? Jeśli tak, czy GCC jest również poprawny w akceptowaniu tego kodu?

Ponadto, pisząc to pytanie, zdałem sobie sprawę, że można całkowicie uniknąć błędu kompilacji klang poprzez usunięcie kwalifikatora constexpr przed szablonem funkcji członka. Co zmienia się tutaj obecność constexpr?


Jaki jest problem jak ja kompilacji z -Werror. Istnieją pewne ostrzeżenia, które są oparte na heurystyce i dlatego mają nieuniknione fałszywe alarmy, ale tak nie jest, o ile widzę.

Odpowiedz

2

Jeśli nie zamierzasz wywoływać funkcji, nie ma sensu oznaczać jej jako constexpr.

constexpr na funkcji nie jest widoczna dla systemu typów (no, poza tym, że pre-C++ 14 miał efekt uboczny tworzenia niestatycznej funkcji składowej const); jest to raczej obietnica, że ​​dla co najmniej jednej kombinacji argumentów typu szablonu i argumentów funkcji (oraz stanu obiektu dla niestatycznej funkcji składowej) treść tej funkcji może być określana jako jako wyrażenie stałe (lub odpowiednik algorytmu). do stałego wyrażenia). Odwrotnie, brak funkcji constexpr jest instrukcją dla kompilatora, aby nawet nie próbować oceniać treści funkcji jako wyrażenia stałego.

Clang nie jest poprawne, dokładnie, ale to nie jest nieprawidłowy, albo, jak już specjalnie poprosił go, aby odrzucić ważne programy (z -Werror). Powinieneś przyjąć ostrzeżenie-błąd jako silną wskazówkę, że funkcje constexpr bez definicji są złym pomysłem.

+0

Tak, całkowicie się zgadzam. Fakt, że wykonałem te funkcje "constexpr", nie ma żadnego sensu. Byłem po prostu zaskoczony, że z pozoru zmienia się sposób, w jaki widzi je nieuwarunkowany kontekst. –

2

Czy to błąd w klangu? Czy też słuszne jest narzekanie? Jeśli tak, to czy GCC jest również poprawny w akceptowaniu tego kodu przez ?

Ponadto, pisząc to pytanie zdałem sobie sprawę, że dzyń kompilacja błędów można uniknąć całkowicie usuwając constexpr kwalifikator przed szablonu funkcji członka. Co tutaj zmienia się obecność constexpr?

Ostrzeżenia kompilatora wykraczają poza standard C++. Ostrzeżenia są wydawane dla ważnych programów, które zawierają wskazania błędu ludzkiego. W twoim przypadku zdecydowałeś się zakwalifikować za pomocą constexpr funkcji, której nie zdefiniowałeś. Programy korzystające z tej klasy będą ważne tylko wtedy, gdy nigdy nie wywołasz tej funkcji. Jeśli tak jest naprawdę, to nie jest potrzebne constexpr. Ale co jeśli zamierzasz wywołać tę funkcję (choć zapomniałeś o jej implementacji), ale z powodu jakiegoś błędu (złożonej rozdzielczości przeciążenia lub po prostu głupiego literówki) wywołano inną funkcję?

W ten sposób firma Clang ma swój punkt w wydaniu ostrzeżenia. Można jednak spierać się, czy sytuacja ta zasługuje na ostrzeżenie; osobiście nie zgłosiłbym błędu przeciwko GCC.

+0

Ostrzeżenie jest generowane na stronie wywołania (które * nie jest * witryną połączeń), dlatego podejrzewam, że jest to błąd: wydaje się, że clang myśli, że zadzwonię do tej funkcji. –

+0

Ostrzeżenie nie jest generowane w witrynie połączenia. Przykład: https://godbolt.org/g/GbWxNp – Leon

+0

Wiem, ale w tym przypadku jest. –

Powiązane problemy