Considere o caso de uma função de modelo com argumentos de modelo variados:
template<typename Tret, typename... T> Tret func(const T&... t);
Agora, tenho uma tupla t
de valores. Como ligo func()
usando os valores da tupla como argumentos? Eu li sobre o bind()
objeto de função, com call()
função, e também a apply()
função em diferentes documentos agora obsoletos. A implementação do GNU GCC 4.4 parece ter uma call()
função na bind()
classe, mas há muito pouca documentação sobre o assunto.
Algumas pessoas sugerem hacks recursivos escritos à mão, mas o verdadeiro valor dos argumentos dos modelos variados é poder usá-los nos casos como acima.
Alguém tem uma solução para é, ou dica sobre onde ler sobre isso?
integer_sequence
, consulte en.cppreference.com/w/cpp/utility/integer_sequenceinteger_sequence S
, você simplesmente chama sua função comofunc(std::get<S>(tuple)...)
e deixa o compilador lidar com o resto.Respostas:
Aqui está o meu código, se alguém estiver interessado
Basicamente, no momento da compilação, o compilador desenrola recursivamente todos os argumentos em várias chamadas de função inclusivas <N> -> chamadas <N-1> -> chamadas ... -> chamadas <0>, que é a última e o compilador será otimizado as várias funções intermediárias chamam para manter apenas a última que é equivalente a func (arg1, arg2, arg3, ...)
São fornecidas duas versões, uma para uma função chamada em um objeto e a outra para uma função estática.
fonte
tr1
material pode se retirado agora com c ++ 11No C ++ 17, você pode fazer isso:
Isso já funciona no Clang ++ 3.9, usando std :: experimental :: apply.
Respondendo ao comentário dizendo que isso não funcionará se
the_function
estiver modelado, o seguinte é uma solução alternativa:Esta solução alternativa é uma solução simplificada para o problema geral de passar conjuntos de sobrecarga e modelo de função onde uma função seria esperada. A solução geral (que cuida do encaminhamento perfeito, do consenso e do não-aceitável) é apresentada aqui: https://blog.tartanllama.xyz/passing-overload-sets/ .
fonte
the_function
estiver com modelo.std::apply(add_generic<float>, std::make_pair(2.0f, 3.0f));
No C ++, existem muitas maneiras de expandir / descompactar a tupla e aplicar esses elementos a uma função de modelo variável. Aqui está uma pequena classe auxiliar que cria uma matriz de índice. É muito usado na metaprogramação de modelos:
Agora, o código que faz o trabalho não é tão grande:
O teste é mostrado abaixo:
Não sou grande especialista em outros idiomas, mas acho que, se esses idiomas não tiverem essa funcionalidade em seu menu, não há como fazê-lo. Pelo menos com C ++ você pode, e acho que não é tão complicado ...
fonte
template<class ... T> void three(T...) {}
e tentar usar apply, ele não compila.Acho que essa é a solução mais elegante (e é encaminhada de maneira ideal):
Exemplo de uso:
Infelizmente, o GCC (4.6 pelo menos) falha ao compilar isso com "desculpe, não foi implementado: sobrecarga de manipulação" (o que significa simplesmente que o compilador ainda não implementa completamente a especificação do C ++ 11) e, como ele usa modelos variados, não trabalhar no MSVC, por isso é mais ou menos inútil. No entanto, quando houver um compilador que suporte as especificações, essa será a melhor abordagem do IMHO. (Nota: não é tão difícil modificar isso para que você possa solucionar as deficiências no GCC ou implementá-lo com o Boost Preprocessor, mas isso arruina a elegância, portanto esta é a versão que estou publicando.)O GCC 4.7 agora suporta esse código muito bem.
Edit: Adicionado adiante em torno da chamada de função real para oferecer suporte ao formulário de referência rvalue * isso no caso de você estar usando o clang (ou se alguém realmente conseguir adicionar isso).
Editar: adicionado em falta ao redor do objeto da função no corpo da função de não-membro aplicar. Agradecemos a pheedbaq por apontar que estava faltando.
Edit: E aqui está a versão do C ++ 14, já que é muito melhor (na verdade ainda não compila):
Aqui está uma versão para funções membro (não muito testada!):
fonte
apply
, por quef
não é encerrada com umastd::forward
chamada, como é no tipo de retorno? Não é necessário?foo('x', true)
compilei exatamente o mesmo código de montagem queapply(foo, ::std::make_tuple('x', true))
com qualquer nível de otimização além de -O0.integer_sequence
você obtém uma implementação quase corretaapply()
em seu exemplo. veja minha resposta abaixo.Isso é adaptado do rascunho do C ++ 14 usando index_sequence. Eu poderia propor a aplicação em um futuro padrão (TS).
fonte
As notícias não parecem boas.
Depois de ler o rascunho do padrão recém-lançado , não vejo uma solução integrada para isso, o que parece estranho.
O melhor lugar para perguntar sobre essas coisas (se você ainda não o fez) é o moderador comp.lang.c ++., Porque algumas pessoas envolvidas na redação do post padrão lá regularmente.
Se você verificar esta discussão , alguém terá a mesma pergunta (talvez seja você; nesse caso, você achará toda essa resposta um pouco frustrante!), E algumas implementações desagradáveis serão sugeridas.
Eu apenas me perguntei se seria mais simples fazer a função aceitar a
tuple
, pois a conversão dessa maneira é mais fácil. Mas isso implica que todas as funções devem aceitar tuplas como argumentos, para máxima flexibilidade e, portanto, apenas demonstra a estranheza de não fornecer uma expansão interna da tupla para o pacote de argumentos da função.Atualização: o link acima não funciona - tente colar o seguinte:
http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/750fa3815cdaac45/d8dc09e34bbb9661?lnk=gst&q=tuple+variadic#d8dc09e34bbb9661
fonte
Todas essas implementações são boas. Porém, devido ao uso do ponteiro para o compilador de função membro, muitas vezes não é possível alinhar a chamada da função de destino (pelo menos o gcc 4.8 não pode, não importa o quê. Por que o gcc não pode alinhar os ponteiros de função que podem ser determinados? )
Mas as coisas mudam se enviar ponteiro para a função membro como argumentos de modelo, não como parâmetros de função:
E uso:
Prova de inlinável http://goo.gl/5UqVnC
Com pequenas alterações, podemos "sobrecarregar"
apply_tuple
:Além disso, esta é a única solução que funciona com funções de modelo.
fonte
1) se você tem uma estrutura de parâmetro_pacote pronto como argumento de função, pode apenas usar std :: tie como este:
2) se você não tiver um argumento de parampack pronto, precisará desenrolar a tupla como esta
fonte
Que tal agora:
O
run_tuple
modelo de função pega a tupla especificada e passa seus elementos individualmente para a função especificada. Ele realiza seu trabalho chamando recursivamente seus modelos de função auxiliarexplode_tuple
. É importante querun_tuple
passe o tamanho da tupla paraexplode_tuple
; esse número atua como um contador para quantos elementos extrair.Se a tupla estiver vazia,
run_tuple
chame a primeira versão doexplode_tuple
com a função remota como o único outro argumento. A função remota é chamada sem argumentos e terminamos. Se a tupla não estiver vazia, um número maior será passado para a segunda versão doexplode_tuple
, juntamente com a função remota. Uma chamada recursiva paraexplode_tuple
é feita, com os mesmos argumentos, exceto que o número do contador é diminuído em um e (uma referência a) o último elemento da tupla é alinhado como argumento após a função remota. Em uma chamada recursiva, o contador não é zero e outra chamada é feita com o contador diminuído novamente e o próximo elemento não referenciado é inserido na lista de argumentos após a função remota, mas antes dos outros argumentos inseridos, ou o contador atinge zero e a função remota é chamada com todos os argumentos acumulados após ele.Não tenho certeza se tenho a sintaxe de forçar uma versão específica de um modelo de função corretamente. Eu acho que você pode usar um ponteiro para função como um objeto de função; o compilador irá corrigi-lo automaticamente.
fonte
Estou avaliando o MSVS 2013RC e ele não conseguiu compilar algumas das soluções anteriores propostas aqui em alguns casos. Por exemplo, o MSVS falhará ao compilar retornos "automáticos" se houver muitos parâmetros de função, devido a um limite de imbricação de namespace (enviei essas informações à Microsoft para corrigi-las). Em outros casos, precisamos acessar o retorno da função, embora isso também possa ser feito com um lamda: os dois exemplos a seguir dão o mesmo resultado.
E obrigado novamente àqueles que postaram respostas aqui antes de mim, eu não teria chegado a isso sem ele ... então aqui está:
fonte
const
?Estendendo-se à solução de @ David, você pode escrever um modelo recursivo que
integer_sequence
semântica (excessivamente verbosa, imo)int N
para contar iterações recursivasPor exemplo:
Como alternativa, se o seu functor não estiver definido em tempo de compilação (por exemplo, uma
constexpr
instância que não seja do functor ou uma expressão lambda), você poderá usá-lo como parâmetro de função em vez de parâmetro de modelo de classe e, de fato, remover completamente a classe que contém:Para chamadas de ponteiro para função de membro, você pode ajustar um dos pedaços de código acima da mesma forma que na resposta de @ David.
Explicação
Em referência ao segundo trecho de código, existem duas funções de modelo: a primeira pega o functor
func
, a tuplat
com tiposT...
e um pacoteargs
de parâmetros de tiposArgs_tmp...
. Quando chamado, adiciona recursivamente os objetos det
ao pacote de parâmetros, um de cada vez, do início (0
) ao fim e chama a função novamente com o novo pacote de parâmetros incrementado.A assinatura da segunda função é quase idêntica à primeira, exceto que ela usa o tipo
T...
para o pacote de parâmetrosargs
. Assim, uma vez queargs
a primeira função é completamente preenchida com os valores det
, seu tipo seráT...
(em código psuedotypeid(T...) == typeid(Args_tmp...)
) e, portanto, o compilador chamará a segunda função sobrecarregada, que por sua vez chamafunc(args...)
.O código no exemplo estático do functor funciona de forma idêntica, com o functor usado como argumento do modelo de classe.
fonte
Por que não apenas agrupar seus argumentos variados em uma classe de tupla e usar a recursão em tempo de compilação (consulte o link ) para recuperar o índice no qual você está interessado. Acho que descompactar modelos variados em um contêiner ou coleção pode não ser do tipo seguro e heterogêneo
fonte
Args...
->tuple
, mastuple
->Args...
.Esta solução simples funciona para mim:
fonte