2014-09-17 24 views
6

Bir işlevin bir const mı yoksa const olmayan bir değer mi döndürdüğünü anlamanın bir yolu var mı? decltype, başvurular için çalışır, ancak başvuru dışı türler için çalışmayacaktır. İşlev tarafından döndürülen türün sabitliğini anlama

#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; 
} 

bir std::tuple her demet elemanı üzerinde bir işlev nesnesini arayıp dönüş türleri oluşan yeni bir tuple saklayacak fonksiyonu dönüşümü uygulanır. Bu oldukça şaşırtıcı (ancak gerekli) const dönüş türleri için işe yaramıyor.

+2

'Aralık ltype, bir dönüş değerinin (fark ettiğiniz gibi) yapısını korumaz. http://stackoverflow.com/questions/18502188/why-does-decltype-remove-const-from-return-types-for-built-in-types – CoryKramer

+1

Sınıf dışı, dizi dışı türler için, hayır, yok Bir şekilde (bildiğim, her zaman umudumu tutabilirim). Sınıf türleri için önemsiz. Örneğinizde 'int 'açıkça bir sınıf tipi ve dizi tipi değildir. – WhozCraig

cevap

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

Çıkış:

false 
true 
false 
true 
false 
true 

LIVE DEMO

+0

Güzel. Bir lambda işlevi verildiğinde, C'nin nasıl açıklandığını açıklayan veya açıklayan bir yere işaret edebilir misiniz? –

+0

Bana öyle geliyor ki, bu hile, bir işlev göstericisine dolaylı olarak dönüştürülemeyecek bir kapanma için işe yaramaz. Çok güzel ve kullanışlı olsa da. – tsuki

+0

Ve ... bir üye fonksiyonunun adresini aldığımızdan bu, aşırı yüklenen operatör() 'için çalışmayacaktır. – tsuki

0

Kalibre edilebilir bir nesnenin dönüş türünü almak için std :: result_of öğesini kullanabilirsiniz.

Bir const int döndürmenin imkansız olduğunu unutmayın, derleyici kalifikasyonu göz ardı eder. GCC'nin bunun için bir uyarısı var. -Wextra -pedantic bir şey onu açar.

5

Yerleşik olmayan türler için, istediğinizi almak üzere std::is_const ve decltype kullanabilirsiniz.

Örnek:

#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; 
} 

Çıkış:

 
false 
true 
İlgili konular