2016-05-19 7 views
11

Poniższy kod wywołuje statyczne twierdzenie o libstdC++:Czy można używać typu decltype na std :: declval <T> (sama funkcja, a nie wynik wywołania)?

#include <utility> 

using t = decltype(std::declval<const void>); 

Powinna?


Motywacja na to pytanie:

Poniższy declval realizacja proposed by Eric Niebler (co jest podobno kompilacji optymalizacja czasu)

template<typename _Tp, typename _Up = _Tp&&> 
_Up __declval(int); 

template<typename _Tp> 
_Tp __declval(long); 

template<typename _Tp> 
auto declval() noexcept -> decltype(__declval<_Tp>(0)); 

byłoby wątpliwe, czy użytkownik może legalnie obserwować typ std::declval<const void> . Podpis w standardowym

template <class T> 
add_rvalue_reference_t<T> declval() noexcept; 

Wyniki w rodzaju const void() (lub const void() noexcept w C++, 17), podczas gdy w wersji proponowanych wyników typu void() (lub void() noexcept).

+0

Co próbujesz osiągnąć z tym? –

+1

@SamVarshavchik, powód pytania wydaje się dość jasne z samego pytania. .. – SergeyA

+3

Biorąc pod uwagę, że to ty zadajesz to pytanie, mam zerową pewność n moja odpowiedź. Ale i tak go wyrzuci. Czy "długie" przeciążenie w propozycji Nieblera dotyczy tylko obsługi cv-'void'? – Barry

Odpowiedz

5

[declval] stanowi:

Jeżeli funkcja ta jest ODR stosowane (3.2), program jest słabo formowane.

To w zasadzie to. W którym funkcje dotyczą, ODR wykorzystanie znaczy w [basic.def.odr]

funkcją którego nazwa pojawia się jako potencjalnie oceniano ekspresję ODR wykorzystywane jeśli jest unikalny wynik wyszukiwania, lub wybrany element zestawu przeciążonych funkcji (3.4, 13.3, 13.4), , chyba że jest to czysta funkcja wirtualna i albo jej nazwa nie jest jednoznacznie określona, ​​albo wyrażenie tworzy jeden wskaźnik na element (5.3.1).

ale również:

wyrażenie jest potencjalnie oceniano chyba że jest unevaluated operandu (punkt 5) lub podwyrażenie nich.

A [dcl.type.simple]

Argument z decltype specyfikacją jest unevaluated operandu (punkt 5).

Tak więc w decltype(std::declval<const void>), std::declval nie jest potencjalnie oceniany i dlatego nie jest odr używany. Ponieważ jest to jedyne kryterium dla programu, który ma być źle sformułowany, a my go nie spotykamy, myślę, że libstdC++ nie jest odpowiedni do wysyłania statycznego asercji.


Chociaż nie sądzę, że jest to rzecz ++. Myślę, że to bardziej pytanie o to, kiedy zostaną wywołane static_assert.LibstdC++ realizacja declval jest.

template<typename _Tp> 
struct __declval_protector 
{  
    static const bool __stop = false; 
    static typename add_rvalue_reference<_Tp>::type __delegate(); 
}; 

template<typename _Tp> 
inline typename add_rvalue_reference<_Tp>::type 
declval() noexcept 
{  
    static_assert(__declval_protector<_Tp>::__stop, 
     "declval() must not be used!"); 
    return __declval_protector<_Tp>::__delegate(); 
} 

Zarówno gcc i brzęk wyzwalacza że static_assert w tym kontekście (ale oczywiście nie z decltype(std::declval<const void>()), chociaż jesteśmy w unevaluated kontekście w obu wypadkach podejrzewam, że to błąd, ale może być po prostu niedookreślone w standardzie, co jest prawidłowe zachowanie w odniesieniu do wyzwalania static_assert s.

+0

Hmm, Znalazłem nowy, który nie wyzwala statycznego assert: 'using t = decltype (static_cast (std :: declval ));'. Mogę zadać osobne pytanie w/r/t, czy w standardzie jest coś, co mówi, że ta obsada nie jest wymagana do działania. –

+0

@ T.C. Spodziewałbym się, że będą miały równoważną ważność, więc nie jestem tam dla ciebie pomocna. Ale nie jestem nawet pewien, czy mam rację. – Barry