Modelli di sovraccarico ambigui


16

Ho il seguente codice di modello

#include <vector>
#include <array>
#include <iostream>

template<typename T1>
void foo(std::vector<T1> bar) {
    std::cout << "GENERIC" << std::endl;
}

template<typename T1>
void foo(std::vector<std::vector<T1>> bar) {
    std::cout << "SPECIFIC (vector)" << std::endl;
}

template<typename T1, int SIZE>
void foo(std::vector<std::array<T1, SIZE>> bar) {
    std::cout << "SPECIFIC (array)" << std::endl;
}

int main() {
    std::vector<std::vector<int>> a(2, std::vector<int> { 1, 2, 3});
    std::vector<std::array<int, 3>> b(2, std::array<int, 3> {4, 5, 6});

    foo(a);
    foo(b);
}

che produce

SPECIFIC (vector)
GENERIC

Mi chiedo perché la versione vector-of-vector viene chiamata con il modello specifico, ma la versione vector-of-array viene chiamata con il generico?


2
Cordiali saluti: è possibile semplificare questo, con lo stesso problema, rimuovendo l'esterno vectorsu tutti loro. Vedi qui
ChrisMM,

@ChrisMM buona cattura. Questo esempio è stato sintetizzato dal mio codice di produzione, dove è necessaria la struttura nidificata.
Xaser,

5
MSVC chiama la versione vettoriale di array: godbolt.org/z/7Gfeb0
R2RT

Risposte:


8
template<typename T1, size_t SIZE>
void foo(std::vector<std::array<T1, SIZE>> bar) {
    std::cout << "SPECIFIC (array)" << std::endl;
}

Dovresti usare std::size_tinvece di int. corri qui

Modifica: in realtà, i tuoi commenti e la mia intuizione sul codice mi hanno portato a approfondire l'argomento. A prima vista, uno sviluppatore di standard (come me) si aspettano compilatore per convertire inta std::size_t(perché sono sia di tipo integrale e implicitamente la conversione è molto banale) e selezionare void foo(std::vector<std::array<T1, SIZE>> bar)come migliore specializzazione. Quindi durante la lettura della pagina di deduzione dell'argomento modello ho trovato questo:

Se viene utilizzato un parametro modello non tipo nell'elenco dei parametri e viene dedotto l'argomento modello corrispondente, il tipo dell'argomento modello dedotto (come specificato nell'elenco dei parametri del modello allegato, il che significa che i riferimenti vengono conservati) deve corrispondere al tipo di parametro del modello non di tipo esattamente, tranne per il fatto che i qualificatori cv vengono eliminati e, tranne nel caso in cui l'argomento del modello sia dedotto da un limite di array, in tal caso è consentito qualsiasi tipo integrale, anche se bool sarebbe sempre vero:

Come sempre, ovviamente, devi leggere più volte di una volta per capire cosa significa :)

Quindi viene fuori un risultato interessante.

La nostra specializzazione desiderata non è già selezionata, ma se il compilatore fosse stato costretto a selezionare, sarebbe un errore.

template<typename T1, int SIZE>
void foo(std::vector<std::array<T1, SIZE>> bar) {
    std::cout << "SPECIFIC (array)" << std::endl;
}

int main() {
    std::vector<std::array<int, 3>> b(2, std::array<int, 3> {4, 5, 6});

    foo(b); // P = std::vector<std::array<int,(int)SIZE>
            // A = std::vector<std::array<int,(unsigned_long)SIZE>>
            // error: deduced non-type template argument does not have the same
            // type as its corresponding template argument */
}

eseguire il codice

Un'altra cosa interessante è:

Se l'argomento del modello non di tipo non fosse stato dedotto, non vi sarebbe alcuna restrizione che costringe l'argomento e i tipi di modello a essere uguali.

#include <vector>
#include <array>
#include <iostream>

template<typename T1, int SIZE>
void foo(std::vector<std::array<T1, SIZE>> bar) {
    std::cout << "SPECIFIC (array)" << std::endl;
}

int main() {
    std::vector<std::array<int, 3>> b(2, std::array<int, 3> {4, 5, 6});

    foo<int,3>(b);
}

eseguire il codice


@Xaser perché il secondo argomento template dell'array è di tipo size_t...
Jean-Baptiste Yunès

2
Considerando il commento di R2RT, sembrano esserci differenze specifiche del compilatore.
Xaser,

8

Penso che questo sia semplicemente dovuto a una riga da[temp.deduct.call]/4

In generale, il processo di detrazione tenta di trovare i valori degli argomenti del modello che renderanno la A dedotta identica alla A

Per chiarire, Asignifica il parametro, da[temp.deduct.call]/1

... deduzione dell'argomento modello con il tipo dell'argomento corrispondente della chiamata (chiamalo A) ...

Come è già stato sottolineato, la modifica template<typename T1, int SIZE>per template<typename T1, size_t SIZE>risolvere il problema che stai vedendo. Come affermato in [temp.deduct.call]/4, il compilatore sta cercando di dedurre un Aidentico a A. Poiché un std::arrayha argomenti template <class T, size_t N>(da [array.syn]), il suo secondo parametro è in realtà size_tno int.

Pertanto, per la deduzione del modello, la tua funzione generica template<typename T1>è in grado di corrispondere esattamente al tipo di A, dove il tuo specialista template<typename T1, int SIZE>non è una corrispondenza esatta . Credo che MSVC sia errato nella sua deduzione.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.