Сигнатура лямбда-функции в шаблонном совпадении специализации на c ++ - 17 - PullRequest
0 голосов
/ 15 января 2019

У меня есть следующий код:

#include <iostream>                                                                                                                         
#include <string>                                                                                                                           
#include <array>                                                                                                                            
#include <map>                                                                                                                              
#include <functional>                                                                                                                       

template<typename T> struct tag {};                                                                                                         

template <typename LambdaType, typename=void>                                                                                               
struct split {                                                                                                                              
    split(LambdaType &&f) {                                                                                                                 
        std::cout << "[]()" << std::endl;                                                                                                   
    }                                                                                                                                       
};                                                                                                                                          

template <typename RetType, typename... ArgTypes>                                                                                           
struct split<std::function<RetType(ArgTypes...)>>  {                                                                                        
    split(std::function<RetType(ArgTypes...)> &&f) {                                                                                        
        std::cout << "std::function" << std::endl;                                                                                          
    };                                                                                                                                      
};                                                                                                                                          

template <typename RetType, typename... ArgTypes>                                                                                           
struct split<RetType(*)(ArgTypes...)> {                                                                                                     
    split(RetType(*f)(ArgTypes...)) {                                                                                                       
        std::cout << "func-ptr" << std::endl;                                                                                               
    };                                                                                                                                      
};                                                                                                                                          

void f1(int) {};                                                                                                                            

int                                                                                                                                         
main(int argc, char **argv) {                                                                                                               

    new split<std::decay<decltype(f1)>::type>(f1);                                                                                          
    new split<std::function<void(int)>>(std::function<void(int)>([](int) {}));                                                              

    /* how can I extract the argument type template pack from lambda ? */                                                                   
    new split([](int){});                                                                                                                   
    return 0;                                                                                                                               
}   

Есть две специализации для split, одна для std::function<RetType(ArgTypes...)> и одна для RetType(*)(ArgTypes...). Для обеих специализаций я получаю аргумент шаблона RetType и ArgTypes... и упаковываю по шаблонам. Однако мне интересно, есть ли способ сделать то же самое с lambda в качестве аргумента?

Как я могу извлечь RetType и ArgTypes... лямбды в специализации для строки new split([](int){})?

Ответы [ 3 ]

0 голосов
/ 15 января 2019

Вы можете пройти через какую-то хитрость, например:

#include <type_traits>

template <typename LambdaType, typename=void>                                                                                               
struct split {                                                                                                                              
    split(LambdaType &&f) { deduce(&LambdaType::operator()); }
    template<class RET, class CLOSURE, class... ARGS>
    void deduce(RET(CLOSURE::*)(ARGS...) const) {
       // You have your return and args here
    }
};                                                                                                                                          


template <typename RetType, typename... ArgTypes>                                                                                           
struct split<RetType(*)(ArgTypes...)> {                                                                                                     
    split(RetType(*f)(ArgTypes...));                                                                                                                                      
};                                                                                                                                  

void f1(int) {};                                                                                                                            

int                                                                                                                                         
main(int argc, char **argv) {                                                                                                               

    split<std::decay_t<decltype(f1)>>{f1};                                                                                          

    /* how can I extract the argument type template pack from lambda ? */                                                                   
    split([](int){});                                                                                                                   
    return 0;                                                                                                                               
}   
0 голосов
/ 15 января 2019

Я нашел один метод, который использует подклассы специализации (видел здесь ):

/* g++ -std=c++17 */
#include <iostream>
#include <string>
#include <array>
#include <map>
#include <functional>

template<typename T> struct tag {};
struct mybase {};

/* subclass specialization on type of operator() of lambda: */
template<class Ld>
struct split : split<decltype(&Ld::operator())>
{
    split(Ld &&f) : split<decltype(&Ld::operator())>(std::forward<Ld>(f)) {};
};

template <typename RetType, typename... ArgTypes>
struct split<std::function<RetType(ArgTypes...)>>  {
    split(std::function<RetType(ArgTypes...)> &&f) {
        std::cout << "std::function" << std::endl;
    };
};

template <typename RetType, typename... ArgTypes>
struct split<RetType(*)(ArgTypes...)> {
    split(RetType(*f)(ArgTypes...)) {
        std::cout << "func-ptr" << std::endl;
    };
};

template <typename RetType, class Cls, typename... ArgTypes>
struct split<RetType(Cls::*)(ArgTypes...) const >  {
    split(const Cls &&f) {
        std::cout << "[]() const" << std::endl;
    };
};

template <typename RetType, class Cls, typename... ArgTypes>
struct split<RetType(Cls::*)(ArgTypes...) >  {
    split(Cls &&f) {
        std::cout << "[]()" << std::endl;
    };
};


void f1(int) {};

int
main(int argc, char **argv) {

    new split<std::decay<decltype(f1)>::type>(f1);
    new split<std::function<void(int)>>(std::function<void(int)>([](int) {}));

    /* no g++-17: */
    //auto l = [](int){};
    //new split<decltype(l)>(std::forward<decltype(l)>(l));

    /* g++-17: */
    new split([](int){});

    return 0;
}
0 голосов
/ 15 января 2019

Вы можете использовать вывод аргумента класса шаблона с std::function:

template <typename LambdaType, typename=void>                                                                                               
struct split {                                                                                                                              
    using StdFunctionType = decltype(std::function{std::declval<LambdaType>()});                                                                                                                                  
};     

Если у вас есть std::function, соответствующий вашей лямбде, вы можете извлечь типы возврата и аргумента, используя специализацию шаблона.

Это работает, потому что std::function имеет руководство по удержанию :

template<class F>
function(F) -> function</*see below*/>;

Если decltype(&F::operator()) имеет форму R(G::*)(A...) (опционально cv -квалифицирован, опционально noexcept, опционально указана ссылка на lvalue) для некоторого типа класса G, то выводимый тип будет std::function<R(A...)>. Эта перегрузка участвует только в разрешении перегрузки, если &F::operator() правильно сформирован, когда рассматривается как неоцененный операнд.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...