2016-11-03 18 views
8

Bir işlevin argüman türlerini bulmak için bir yönteme ihtiyacım var ve bu yüzden Is it possible to figure out the parameter type and return type of a lambda?'dan esinlenerek, aşağıda verilen bir closure_traits sınıfı yazdım. Bununla birlikte, basit bir lambdaya uyguladığımda, 'operator()' '(lambda tipi)' nin bir üyesi olmadığı hatası alıyorum. Bununla birlikte, cepheye göre, lambda'nın bir operatörü vardır(). Ayrıca std :: function kullanmayı denedim ve eşdeğer hatayı aldım. Neyin yanlış gittiğinden emin değilim ve herhangi bir yardım büyük takdir edilecektir.C++ Lambda işleç sahibi()

#include<type_traits> 
#include<tuple>                   
#include<utility> 
#include<iostream>                          

/* For generic types use the type signature of their operator() */              
template <typename T>                      
struct closure_traits : public 
         closure_traits<decltype(&T::operator())> {};           

/* Otherwise, we do a template match on a function type. */ 
template <typename ClassType, typename ReturnType, 
      typename... ArgTypes>             
struct closure_traits<ReturnType (ClassType::*) (ArgTypes... args)>             
{ 
    using arity = std::integral_constant<std::size_t, 
             sizeof...(ArgTypes)>;            
    using Ret = ReturnType;         

    /* The argument types will be the same as the types of the 
    * elements of a tuple composed of them. 
    */                        
    template <std::size_t I>  
    struct Args {   
     using type = typename std::tuple_element<I, 
             std::tuple<ArgTypes...>>::type;                              
    };                                                           

};                                                             

int main() {                              
    auto thing = [=] (int x) {return x;}; 

    std::cerr << "The number of arguments is " 
       << closure_traits<decltype(thing)>::arity << std::endl;                              

    return 0;                              
}  

Getirdiğim derleyici hata iletileri aşağıdadır. Derleme komutum sadece g ++ -std = C++ 14 main.cpp şeklindedir.

main.cpp: In instantiation of ‘struct closure_traits<int (main()::<lambda(int)>::*)(int) const>’: 
main.cpp:9:8: required from ‘struct closure_traits<main()::<lambda(int)> >’ 
main.cpp:34:82: required from here 
main.cpp:9:56: error: ‘operator()’ is not a member of ‘int (main()::<lambda(int)>::*)(int) const’ 
struct closure_traits : public closure_traits<decltype(&T::operator())> {};           
                ^
main.cpp: In function ‘int main()’: 
main.cpp:34:51: error: ‘arity’ is not a member of ‘closure_traits<main()::<lambda(int)> >’ 
std::cerr << "The number of arguments is " << closure_traits<decltype(thing)>::arity << std::endl; 
+0

Şablonlardaki "auto" argümanları nedeniyle bunun neden C++ 14'te kötü bir fikir olduğunu biliyorsunuz, değil mi? "Bu türden kaç argüman" sorusu genellikle daha iyi bir fikirdir. – Yakk

+0

Sorunu anladığımdan emin değilim. Fonksiyonun argümanlarının sayısını ve türlerini çıkarmaya çalışıyorum. Bu neden otomatik olarak etkileniyor? – sangrey

+1

Tasarımınız temelde [] (otomatik x) {std :: cout << x << "\ n";} 'yi destekleyemez. C++ içindeki Callables, sabit sayıda argüman içermez ve argümanlarının sabit tiplerine sahip değildir. C++ 'da bir int'nin temelini belirlemeye çalışmak gibidir: kavram,' int '* bir tabana sahip olmadığı için gerçekten geçerli değildir.Sizin durumunuzda, * bazı * callables için, sorunu karıştıran sabit aritmetik ve argüman türlerine sahip olabilirsiniz. – Yakk

cevap

8

Uzmanlık decltype(&T::operator()) argüman eşleşmiyor. Bu nedenle, uzmanlaştırmayı seçmek yerine (istediğiniz gibi), derleyici, aynı ana şablonu tekrarlı olarak seçmeye zorlanır. Üste | Hangisi daha önce bir kez uygulandıktan sonra &T::operator() ifadesini tekrar uygular. I.e &T::operator() yapmanın ilk denemesi başarılı olmakla birlikte, daha sonra derleyici 'u, T zaten int (main()::<lambda(int)>::*)(int) const olduğu zaman tekrar uygulamayı dener. İkincisi, açıkça, bu hata iletisini alıyorsunuz, bu nedenle operator() yok.

Uzmanlığınızı seçememesinin nedeni, şablon parametresi bildiriminde const eksik. Lambda'nın operator(), aslında lambda sınıfının bir const üyesidir. senin uzmanlık

template <typename ClassType, typename ReturnType, 
      typename... ArgTypes>             
struct closure_traits<ReturnType (ClassType::*) (ArgTypes... args) const> 
... 

beyanına const ekle bir derleyici izlemeniz için amaçlanan uzmanlaşma yolunu izleyecektir.

Ve elbette, closure_traits<decltype(thing)>::arity::value, sadece closure_traits<decltype(thing)>::arity değil, yazdırmanız gerekir.

+0

Sanırım "uzmanlık yok * eşleşmiyor" demek – harmic

+0

Teşekkürler! İşe yaradı. – sangrey

4

Derleyici, lambda türünün doğru bir şekilde operator() değerini alır, ancak bu üye işlevine ilişkin bir işaretçi, const niteleyici nedeniyle uzmanlığınızla eşleşmiyor.

Sen (Evet, şablonlar yazma bir işlev türü acı çekmek için.) Ikinci bir ihtisas

template <typename ClassType, typename ReturnType, 
      typename... ArgTypes>             
struct closure_traits<ReturnType (ClassType::*) (ArgTypes... args) const>             
{ 
    // ... 
}; 

eklemek gerekir aşağıdaki gibi durum herkes de

+1

İşlev alan şablon yazmak acı verici değildir: sadece ör. typename Callable ve geri kalan her şey için endişelenme. Typename Container ile aynı. – rubenvb

1

doğru kod bu sorun var:

#include<type_traits> 
#include<tuple>                   
#include<utility> 
#include<iostream>                          

/* For generic types use the type signature of their operator() */              
template <typename T>                      
struct closure_traits : public 
         closure_traits<decltype(&T::operator())> {};           

/* Otherwise, we do a template match on a function type. */ 
template <typename ClassType, typename ReturnType, 
      typename... ArgTypes>             
struct closure_traits<ReturnType (ClassType::*) (ArgTypes... args) const>             
{ 
    using arity = std::integral_constant<std::size_t, 
             sizeof...(ArgTypes)>;            
    using Ret = ReturnType;         

    /* The argument types will be the same as the types of the 
    * elements of a tuple composed of them. 
    */                        
    template <std::size_t I>  
    struct Args {   
     using type = typename std::tuple_element<I, 
             std::tuple<ArgTypes...>>::type;                              
    };                                                           

};                                                             

int main() {                              
    auto thing = [=] (int x) {return x;}; 

    std::cerr << "The number of arguments is " 
       << closure_traits<decltype(thing)>::arity::value << std::endl;                              

    return 0;                              
}