C ++ especializa um lambda para um determinado tipo [duplicado]

9

Eu estava brincando com o lambda "sobrecarregado" como apresentado aqui , e rapidamente chegou ao ponto em que eu acharia conveniente criar fechamentos lambda especializados. Então eu fui a primeira tentativa e erro um pouco, com o meu julgamento mais promissor sendo

auto call_for_vector = [] template<typename T> (std::vector<T>) {};

No entanto, uma análise posterior da cppreference mostrou que nem isso nem construções semelhantes parecem ser permitidas pelo padrão.

Qual é o motivo pelo qual tais especializações não são compatíveis?

Sei que é possível obter esse comportamento usando o SFINAE, mas é menos legível, mais difícil de escrever e mais propenso a erros. É claro que também é possível escrever uma classe com um operator() apropriado, mas isso é soo C ++ 03: -)

Qual seria o uso de tal sintaxe?:

Um exemplo, isso permitiria uma "sobrecarga" de lambda fácil, como no código a seguir

template <class F1, class F2>
struct overload_set : F1, F2
{
    overload_set(F1 x1, F2 x2) : F1(x1), F2(x2) {}
    using F1::operator();
    using F2::operator();
};

template <class F1, class F2>
overload_set<F1,F2> overload(F1 x1, F2 x2)
{
    return overload_set<F1,F2>(x1,x2);
} 

auto f = overload(
         [](auto&& x){ std::cout<<"call by default"<<std::endl;},
         [] template<typename T>(std::vector<T>){std::cout<<"call for vector"<<std::endl;}
         );

Pode-se obter este comportamento, por ex. usando SFINAE base na técnica em esta resposta , mas novamente ... isso é péssimo.

Existe uma solução fácil para SFINAE para obter sobrecargas específicas?

    
por davidhigh 14.02.2016 в 16:36
fonte

1 resposta

2

Este tipo de codificação pode parecer supérfluo no início, mas existem algumas propriedades interessantes que podemos aproveitar. Em relação ao post que você mencionou, eu estava planejando uma parte 2, onde eu mostraria uma maneira interessante de verificar se um tipo tem um membro específico (função ou dados). Digamos que você queira verificar uma função de membro serialize ; em vez de usar mecanismos complicados, descobri que é tão fácil quanto:

auto hs = overload( 
    [ ](auto&& x) -> decltype(x.serialize(2), std::true_type{}) { 
        return{}; },       // ^^ this guy ^^ 
    [ ](...) -> std::false_type { return {}; }); 

demo

Os detalhes da evolução padrão podem ser encontrados aqui , mas a razão pela qual eu postei isso é defender essa sintaxe que, se tivéssemos tido, o acima poderia ser estendido para permitir ordenação parcial entre "sobrecarregado" genérico lambdas :

auto do_something = overload( 
    [ ]<class X>(shared_ptr<X> x) -> decltype(x.serialize(2), std::true_type{}) { 
        /*do something specific for shared ptrs of X */ return{}; },      
    [ ]<class X>(X& x) -> decltype(x.serialize(2), std::true_type{}) { 
        /*do a generic operation for other types that have serialize*/return{}; },      
    [ ](...) -> std::false_type { /*do nothing*/ return {}; }); 
    
por Nikos Athanasiou 20.02.2016 / 21:35
fonte