No C ++ 14, os contêineres associativos parecem ter mudado do C ++ 11 - [associative.reqmts] / 13 diz:
Os modelos de função de membro
find
,count
,lower_bound
,upper_bound
, eequal_range
não devem participar de resolução de sobrecarga, a menos que o tipoCompare::is_transparent
existe.
Qual é o objetivo de tornar um comparador "transparente"?
C ++ 14 também fornece modelos de biblioteca como este:
template <class T = void> struct less {
constexpr bool operator()(const T& x, const T& y) const;
typedef T first_argument_type;
typedef T second_argument_type;
typedef bool result_type;
};
template <> struct less<void> {
template <class T, class U> auto operator()(T&& t, U&& u) const
-> decltype(std::forward<T>(t) < std::forward<U>(u));
typedef *unspecified* is_transparent;
};
Assim, por exemplo, std::set<T, std::less<T>>
que não têm um comparador transparente, mas std::set<T, std::less<>>
se tiver um.
Que problema isso resolve e muda a forma como os contêineres padrão funcionam? Por exemplo, os parâmetros do modelo de std::set
ainda são Key, Compare = std::less<Key>, ...
, de modo que o conjunto padrão perder seus find
, count
etc. membros?
Respostas:
Veja a resposta de Dietmar e resposta de remyabel .
Não, não por padrão.
As novas sobrecargas de modelo de função de membro
find
etc. permitem que você use um tipo que é comparável à chave do contêiner, em vez de usar o próprio tipo de chave. Veja N3465 de Joaquín Mª López Muñoz para justificativa e uma proposta detalhada e cuidadosamente escrita para adicionar este recurso.Na reunião de Bristol, o LWG concordou que o recurso de pesquisa heterogênea era útil e desejável, mas não podíamos ter certeza de que a proposta de Joaquín seria segura em todos os casos. A proposta do N3465 teria causado sérios problemas para alguns programas (consulte a seção Impacto no código existente ). Joaquín preparou um projeto de proposta atualizado com algumas implementações alternativas com diferentes compensações, o que foi muito útil para ajudar o LWG a entender os prós e os contras, mas todos corriam o risco de quebrar alguns programas de alguma forma, então não houve consenso para adicionar o recurso. Decidimos que, embora não seja seguro adicionar o recurso incondicionalmente, seria seguro se fosse desabilitado por padrão e apenas "opt in".
A principal diferença da proposta do N3657 (que foi uma revisão de última hora por mim e STL com base no N3465 e um rascunho não publicado posteriormente por Joaquín) foi adicionar o
is_transparent
tipo como o protocolo que pode ser usado para optar pela nova funcionalidade.Se você não usar um "functor transparente" (ou seja, um que defina um
is_transparent
tipo), os contêineres se comportam da mesma forma que sempre, e esse ainda é o padrão.Se você escolher usar
std::less<>
(o que é novo para C ++ 14) ou outro tipo de "functor transparente", obterá a nova funcionalidade.Usar
std::less<>
é fácil com modelos de alias:O nome
is_transparent
vem do N3421 da STL que adicionou os "operadores de diamante" ao C ++ 14. Um "functor transparente" é aquele que aceita qualquer tipo de argumento (que não precisa ser o mesmo) e simplesmente encaminha esses argumentos para outro operador. Tal functor passa a ser exatamente o que você deseja para pesquisa heterogênea em containers associativos, então o tipois_transparent
foi adicionado a todos os operadores de diamante e usado como o tipo de tag para indicar que a nova funcionalidade deve ser habilitada em containers associativos. Tecnicamente, os contêineres não precisam de um "functor transparente", apenas um que suporte chamá-lo com tipos heterogêneos (por exemplo, opointer_comp
tipo em https://stackoverflow.com/a/18940595/981959 não é transparente de acordo com a definição do STL,pointer_comp::is_transparent
permite que seja usado para resolver o problema). Se você apenas pesquisa em seustd::set<T, C>
com chaves do tipoT
ouint
entãoC
só precisa ser chamado com argumentos do tipoT
eint
(em qualquer ordem), não precisa ser verdadeiramente transparente. Usamos esse nome em parte porque não poderíamos encontrar um nome melhor (eu teria preferidois_polymorphic
porque esses functores usam polimorfismo estático, mas já existe umstd::is_polymorphic
traço de tipo que se refere ao polimorfismo dinâmico).fonte
<>
na proposta vinculada, mas essa proposta não foi introduzida<>
- é a sintaxe existente para uma lista de parâmetros de modelo vazia. "Functores de operador de diamante" seria um pouco menos confuso.Em C ++ 11 não existem modelos de membros
find()
,lower_bound()
etc. Ou seja, nada é perdido por esta mudança. Os modelos de membro foram introduzidos com o n3657 para permitir o uso de chaves heterogêneas com os contêineres associativos. Não vejo nenhum exemplo concreto em que isso seja útil, exceto o exemplo que é bom e ruim!O
is_transparent
uso destina-se a evitar conversões indesejadas. Se os modelos de membro não tivessem restrições, o código existente poderia passar por objetos diretamente que teriam sido convertidos sem os modelos de membro. O caso de uso de exemplo de n3657 é localizar um objeto em umstd::set<std::string>
literal de string usando: com a definição do C ++ 11, umstd::string
objeto é construído ao passar literais de string para a função de membro correspondente. Com a mudança, é possível usar o literal de string diretamente. Se o objeto de função de comparação subjacente for implementado exclusivamente em termosstd::string
disso, isso é ruim porque agora umstd::string
seria criado para cada comparação. Por outro lado, se o objeto de função de comparação subjacente pode levar umstd::string
e um literal de string, que pode evitar a construção de um objeto temporário.O
is_transparent
tipo aninhado no objeto de função de comparação fornece uma maneira de especificar se a função de membro modelada deve ser usada: se o objeto de função de comparação pode lidar com argumentos heterogêneos, ele define esse tipo para indicar que ele pode lidar com argumentos diferentes de forma eficiente. Por exemplo, os novos objetos de função de operador apenas delegamoperator<()
e afirmam ser transparentes. Isso, pelo menos, funciona para ostd::string
que tem sobrecarregado menos do que os operadores tomandochar const*
como argumento. Uma vez que esses objetos de função também são novos, mesmo que façam a coisa errada (ou seja, exijam uma conversão para algum tipo), não seria, pelo menos, uma mudança silenciosa resultando em uma degradação do desempenho.fonte
is_transparent
é definido no objeto de função de comparação de acordo com 23.2.4 [associative.reqmts] parágrafo 13. Os objetos de função de comparação padrão estão destd::less<Key>
acordo com 23.4.2 [associative.map.syn] e 23.4. 3 [associative.set.syn]. De acordo com 20.10.5 [de comparação] parágrafo 4 o modelo geral parastd::less<...>
que não definem um tipo aninhadois_transparent
mas astd::less<void>
especialização faz. Ou seja, não, você não obtém um operador transparente por padrão.is_transparent
?O seguinte é todo copy-pasta do n3657 .
Para citar Yakk ,
e n3657,
n3421 fornece um exemplo de " Funções de operador transparentes" .
O código completo está aqui .
fonte
std::set<std::string>
realmente beneficiar de "passar ochar const *
meio", ou que você precisa para fazer umstd::set<std::string, std::less<>>
?With the change proposed by N3465 the std::set::find() function would be an unconstrained template which would pass the const char* through to the comparator function, std::less<std::string>, which would construct a std::string temporary for every comparison. The LWG considered this performance problem to be a serious issue.
Stephan T Lavavej fala sobre problemas em que o compilador continua criando temporários, e como sua proposta de functores de operador transparentes resolverá isso em c ++ 1y
GoingNative 2013 - Não ajude o compilador (por volta da marca de uma hora)
fonte