2016-05-19 8 views
11

Il seguente codice innesca un'asserzione statico sul libstdC++:È consentito utilizzare decltype su std :: declval <T> (la funzione stessa, non il risultato della chiamata)?

#include <utility> 

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

Dovrebbe?


La motivazione per questa domanda:

Il seguente declval implementazione proposed by Eric Niebler (che è apparentemente un ottimizzazione del tempo di compilazione)

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)); 

sarebbe discutibile se un utente potrebbe legalmente osservare il tipo di std::declval<const void> . La firma nello standard

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

risultati nel tipo const void() (o const void() noexcept in C++ 17), considerando che gli risultati versione del tipo void() (o void() noexcept).

+0

Cosa stai cercando di ottenere con questo? –

+1

@ SamVarshavchik, il motivo della domanda sembra abbastanza chiaro dalla domanda stessa. .. – SergeyA

+3

Dato che sei tu a fare questa domanda, ho zero fiducia in me n la mia risposta. Ma buttarlo fuori comunque. Il sovraccarico 'lungo? Nella proposta di Niebler è sufficiente per gestire cv-'void'? – Barry

risposta

5

[declval] stabilisce che:

Se viene ODR-usato questa funzione (3.2), il programma è mal-formata.

Questo è fondamentalmente. Dove le funzioni sono interessati, ODR utilizzare consente, da [basic.def.odr]:

Una funzione cui nome appare come un'espressione potenzialmente valutato viene utilizzato ODR- se è il risultato della ricerca unico o la membro selezionato di un insieme di funzioni sovraccariche (3.4, 13.3, 13.4), a meno che non si tratti di una funzione virtuale pura e il suo nome non è esplicitamente qualificato oppure l'espressione forma un puntatore al membro (5.3.1).

Ma anche:

un'espressione viene valutata potenzialmente meno che non sia un operando non valutata (punto 5) o una sottoespressione stessa.

E [dcl.type.simple]:

L'operando della decltype specificatore è un operando non valutata (clausola 5).

Quindi in decltype(std::declval<const void>), std::declval non è potenzialmente valutato e quindi non è odr-used. Poiché questo è uno dei criteri su declval perché il programma sia mal formato e non lo si incontra, penso che libstdC++ non sia in grado di emettere l'asserzione statica.


Anche se non penso che sia una cosa di libstC++. Penso che sia più una questione di quando vengono attivati ​​i numeri static_assert s.L'implementazione libstdC++ di declval è:.

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(); 
} 

Sia gcc e grilletto clang che static_assert in questo contesto (ma ovviamente non con decltype(std::declval<const void>()), anche se siamo in un contesto non valutata in entrambi i casi ho il sospetto che sia un bug, ma può essere semplicemente sottostimato nello standard qual è il comportamento corretto per quanto riguarda l'attivazione di static_assert s.

+0

Hmm, ne ho trovato uno nuovo che non attiva l'asser statico: 'usando t = decltype (static_cast (std :: declval ));'. Potrei fare una domanda separata senza che ci sia qualcosa nello standard che dice che questo cast non è richiesto per funzionare. –

+0

@ T.C. Mi sarei aspettato che avessero una validità equivalente, quindi non vi sono d'aiuto. Ma non sono nemmeno sicuro di avere ragione su questo. – Barry

Problemi correlati