os tipos de modelo devem seguir um "conceito" (Iterador de entrada, Iterador de avanço, etc ...) onde os detalhes reais do conceito são definidos inteiramente pela implementação da função / classe do modelo, e não pela classe do tipo usado com o modelo, que é um pouco anti-uso de OOP.
Eu acho que você entende mal o uso pretendido dos conceitos pelos modelos. O Iterator para frente, por exemplo, é um conceito muito bem definido. Para encontrar as expressões que devem ser válidas para que uma classe seja um Iterador Direto e suas semânticas, incluindo a complexidade computacional, consulte o padrão ou http://www.sgi.com/tech/stl/ForwardIterator.html (você precisa seguir os links para Entrada, Saída e Trivial Iterator para ver tudo).
Esse documento é uma interface perfeitamente boa e "os detalhes reais do conceito" são definidos ali mesmo. Eles não são definidos pelas implementações dos Forward Iterators, nem pelos algoritmos que usam os Forward Iterators.
As diferenças em como as interfaces são tratadas entre STL e Java são triplas:
1) STL define expressões válidas usando o objeto, enquanto Java define métodos que devem ser chamados no objeto. Obviamente, uma expressão válida pode ser uma chamada de método (função de membro), mas não precisa ser.
2) As interfaces Java são objetos de tempo de execução, enquanto os conceitos STL não são visíveis no tempo de execução, mesmo com o RTTI.
3) Se você não conseguir validar as expressões válidas necessárias para um conceito STL, receberá um erro de compilação não especificado ao instanciar algum modelo com o tipo. Se você não conseguir implementar um método necessário de uma interface Java, receberá um erro de compilação específico dizendo isso.
Esta terceira parte é se você gosta de uma espécie de "digitação de pato" (em tempo de compilação): as interfaces podem estar implícitas. Em Java, as interfaces são um pouco explícitas: uma classe "é" Iterável se e somente se diz que implementa Iterable. O compilador pode verificar se as assinaturas de seus métodos estão todas presentes e corretas, mas a semântica ainda está implícita (ou seja, está documentada ou não, mas apenas mais código (testes de unidade) pode indicar se a implementação está correta).
No C ++, como no Python, a semântica e a sintaxe estão implícitas, embora no C ++ (e no Python, se você obtiver o pré-processador de digitação forte), obtenha ajuda do compilador. Se um programador exigir declaração explícita de interfaces do tipo Java pela classe de implementação, a abordagem padrão é usar traços de tipo (e a herança múltipla pode impedir que isso seja muito detalhado). O que está faltando, em comparação com Java, é um modelo único que eu posso instanciar com meu tipo e que será compilado se e somente se todas as expressões necessárias forem válidas para meu tipo. Isso me diria se eu implementei todos os bits necessários "antes de usá-lo". Essa é uma conveniência, mas não é o cerne da OOP (e ainda não testa semântica,
O STL pode ou não ser suficientemente OO para o seu gosto, mas certamente separa a interface de maneira limpa da implementação. Não possui a capacidade do Java de refletir sobre interfaces e relata violações dos requisitos de interface de maneira diferente.
você pode dizer à função ... espera um Iterador Direto apenas observando sua definição, onde seria necessário examinar a implementação ou a documentação para ...
Pessoalmente, acho que os tipos implícitos são uma força, quando usados adequadamente. O algoritmo diz o que faz com seus parâmetros de modelo e o implementador garante que essas coisas funcionem: é exatamente o denominador comum do que "interfaces" devem fazer. Além disso, com o STL, é improvável que você esteja usando, digamos, com std::copy
base em encontrar sua declaração de encaminhamento em um arquivo de cabeçalho. Os programadores devem estar trabalhando no que uma função leva com base em sua documentação, não apenas na assinatura da função. Isso é verdade em C ++, Python ou Java. Existem limitações sobre o que pode ser alcançado com a digitação em qualquer idioma, e tentar usar a digitação para fazer algo que não faz (verifique a semântica) seria um erro.
Dito isto, os algoritmos STL geralmente nomeiam seus parâmetros de modelo de uma maneira que deixa claro qual conceito é necessário. No entanto, isso é para fornecer informações extras úteis na primeira linha da documentação, para não tornar as declarações avançadas mais informativas. Há mais coisas que você precisa saber do que o que pode ser encapsulado nos tipos de parâmetros; portanto, você deve ler os documentos. (Por exemplo, em algoritmos que utilizam um intervalo de entrada e um iterador de saída, é provável que o iterador de saída precise de "espaço" suficiente para um determinado número de saídas com base no tamanho da faixa de entrada e talvez nos valores contidos nela. Tente digitar isso com força. )
Aqui está Bjarne em interfaces explicitamente declaradas: http://www.artima.com/cppsource/cpp0xP.html
Em genéricos, um argumento deve ser de uma classe derivada de uma interface (o equivalente em C ++ à interface é uma classe abstrata) especificada na definição do genérico. Isso significa que todos os tipos de argumentos genéricos devem caber em uma hierarquia. Isso impõe restrições desnecessárias aos projetos, requer uma previsão irracional por parte dos desenvolvedores. Por exemplo, se você escrever um genérico e eu definir uma classe, as pessoas não poderão usar minha classe como argumento para o seu genérico, a menos que eu conheça a interface que você especificou e tenha derivado minha classe dela. Isso é rígido.
Analisando o contrário, com a digitação de pato, você pode implementar uma interface sem saber que ela existe. Ou alguém pode escrever uma interface deliberadamente, para que sua classe a implemente, após consultar seus documentos para ver se eles não pedem nada que você ainda não faz. Isso é flexível.