2014-09-17 13 views
6

C'è un modo per dire se una funzione restituisce un valore const o un valore non const? decltype funziona per i riferimenti, ma non funzionerà con i tipi non di riferimento.Deducing constness del tipo restituito dalla funzione

#include <type_traits> 

template<typename> 
struct print_type;  //undefined 

int main(){ 
    auto lambda = []()->const int{ return 0; }; 
    print_type< decltype(lambda()) > dt; //print_type<int> 
    print_type< typename std::result_of<decltype(lambda)()>::type > ro; 
    //print_type<int> 


    return 0; 
} 

ho implementato un std::tuple funzione, che chiamerà un oggetto funzione su ogni elemento tupla e memorizzare il risultato in una nuova tuple composto tipi restituiti trasformazione. Questo non funziona per i tipi di ritorno const, che è piuttosto sorprendente (ma necessario).

+2

'dicembre ltype' non manterrà il 'const'-ness di un valore di ritorno (come hai notato). http://stackoverflow.com/questions/18502188/why-does-decltype-remove-const-from-return-types-for-built-in-types – CoryKramer

+1

Per i tipi non-class, non-array, no, non c'è È un modo (che io sappia, posso sempre dare speranza). Per i tipi di classe è banale. Nel tuo esempio 'int' non è ovviamente né un tipo di classe, né un tipo di array. – WhozCraig

risposta

3
#include <iostream> 
#include <type_traits> 
#include <utility> 

template <typename T> 
struct has_operator 
{  
    template <typename U> 
    struct SFINAE {}; 

    template <typename U> 
    static std::true_type test(SFINAE<decltype(&U::operator())>*); 

    template <typename U> 
    static std::false_type test(...); 

    static constexpr bool value = std::is_same<decltype(test<T>(nullptr)), std::true_type>::value; 
}; 

template <bool value, typename T> 
struct check_constness; 

template <typename T> 
struct check_constness<false, T> 
{   
    template <typename R, typename... Args> 
    static std::true_type const_or_not(const R(*)(Args...)); 

    static std::false_type const_or_not(...); 

    using type = decltype(const_or_not(std::declval<T*>())); 
}; 

template <typename T> 
struct check_constness<true, T> 
{   
    template <typename R, typename C, typename... Args> 
    static std::true_type const_or_not(const R(C::*)(Args...)); 

    template <typename R, typename C, typename... Args> 
    static std::true_type const_or_not(const R(C::*)(Args...) const); 

    template <typename R, typename C, typename... Args> 
    static std::true_type const_or_not(const R(C::*)(Args...) const volatile); 

    template <typename R, typename C, typename... Args> 
    static std::true_type const_or_not(const R(C::*)(Args...) volatile); 

    static std::false_type const_or_not(...); 

    using type = decltype(const_or_not(&T::operator())); 
}; 

template <typename T> 
using is_const_ret_type = typename check_constness<has_operator<T>::value, T>::type; 

int glob() { return 0; } 
const int cglob() { return 0; } 

int main() 
{ 
    std::cout << std::boolalpha; 
    int x = 123; 

    auto lambda = []() -> int { return 0; }; 

    auto clambda = []() -> const int { return 0; }; 

    auto closure = [x]() -> int { return x; }; 

    auto cclosure = [x]() -> const int { return x; }; 

    std::cout << is_const_ret_type<decltype(lambda)>::value << std::endl; 

    std::cout << is_const_ret_type<decltype(clambda)>::value << std::endl; 

    std::cout << is_const_ret_type<decltype(glob)>::value << std::endl; 

    std::cout << is_const_ret_type<decltype(cglob)>::value << std::endl; 

    std::cout << is_const_ret_type<decltype(closure)>::value << std::endl; 

    std::cout << is_const_ret_type<decltype(cclosure)>::value << std::endl; 
} 

uscita:

false 
true 
false 
true 
false 
true 

LIVE DEMO

+0

Bello. Puoi spiegare, o indicare un punto che spiega, come viene dedotto 'C' dato una funzione lambda? –

+0

Mi sembra che questo trucco non funzioni per una chiusura in quanto non è implicitamente convertibile in un puntatore a funzione. Molto bello e utile però. – tsuki

+0

E ... visto che stiamo prendendo un indirizzo di una funzione membro, questo non funzionerà con 'operator()' sovraccarico. – tsuki

0

È possibile utilizzare std :: result_of per ottenere il tipo restituito di un oggetto callable.

Ricordare che restituire un const const è impossibile, il compilatore ignorerà la qualifica. GCC ha un avvertimento per questo. Qualcosa in -Wall -Wextra -pedantic lo accende.

5

Per tipi non incorporati, è possibile utilizzare std::is_const e decltype per ottenere ciò che si desidera.

Esempio:

#include <iostream> 
#include <type_traits> 

struct A {}; 

int main() 
{ 
    std::cout << std::boolalpha; 
    { 
     auto lambda = []()->A{ return A(); }; 
     std::cout << std::is_const<decltype(lambda())>::value << std::endl; 
    } 

    { 
     auto lambda = []()->const A{ return A(); }; 
     std::cout << std::is_const<decltype(lambda())>::value << std::endl; 
    } 

    return 0; 
} 

uscita:

 
false 
true 
Problemi correlati