2012-04-25 14 views
5

nie mogę dowiedzieć się, dlaczego następujący kod kompiluje grzywny:C++ Template Funkcja instantiaion parametrów ukrytych

#include <iostream>                 

void bar(int x) {                 
    std::cout << "int " << x << std::endl;            
}                     

void bar(double x) {                 
    std::cout << "double " << x << std::endl;           
}                     

template <typename A, typename B> // Note the order of A and B.            
void foo(B x) {                  
    bar((A)x);                   
}                     

int main() {                   
    int x = 1;                   
    double y = 2;                  

    foo<int>(x);  // Compiles OK.                
    foo<double>(y);  // Compiles OK.            

    return 0;                   
} 

Ale jeśli mogę przełączyć kolejność A i B jak poniżej, to nie będzie skompilować:

#include <iostream>                 

void bar(int x) {                 
    std::cout << "int " << x << std::endl;            
}                     

void bar(double x) {                 
    std::cout << "double " << x << std::endl;           
}                     

template <typename B, typename A> // Order of A and B are switched. 
void foo(B x) {                  
    bar((A)x);                   
}                     

int main() {                   
    int x = 1;                   
    double y = 2;                  

    foo<int>(x);  // error: no matching function for call to ‘foo(int&)’ 
    foo<double>(y);  // error: no matching function for call to ‘foo(double&)’                

    return 0;                   
}  

EDIT: Ad-hoc wyjaśnienia są mile widziane, ale byłoby lepiej, jeśli ktoś może wskazać dokładny co spec. mówi. Dzięki!

+1

Kompilator może wywnioskować typ B w pierwszym przykładzie z parametru przekazanego do konstruktora foo (typu B). W drugim przykładzie nie można dokonać takiego wnioskowania, ponieważ podany parametr szablonu to B, a zatem jest to parametr konstruktora. Rodzaj A nie jest widoczny. – Stabledog

Odpowiedz

7

W pierwszym z nich, kompilator wie, że A jest int ponieważ wyraźnie powiedzieć to tak z foo<int>, i wie, że jest również intB ze względu na parametr, który możesz przekazać go. Tak więc, zarówno A, jak i B są znane lub można je wydedukować (można powiedzieć: A jest dostarczone, B jest domyślnie ).

Jednak w drugim, ponieważ jest na pierwszym miejscu, a A nie pojawia się na liście parametrów, kompilator nie może stwierdzić, co to jest A i daje błąd. Mówisz jednoznacznie, co to jest B z foo<int>, a następnie parametr, który przekazujesz, to także B, który podczas wywołania jest int, który zgadza się z twoją poprzednią wyraźną definicją B, ale nie wspomina się o A, niejawnie lub jawnie, więc kompilator musi przestać i błąd.

Tak naprawdę nie potrzebujesz standardu, to tylko zdrowy rozsądek. Co, u licha, miałoby być w drugim przypadku na A?

Dziękuję za zadawanie tego pytania, ponieważ nie zdawałem sobie sprawy, że można jawnie określić niektóre parametry i niejawnie określić inne w liście parametrów przed tym.

+0

To staje się pytaniem o specyfikację. mówi o tym, jak określa się "A" i "B". Kompilator mógł określić "B" ze względu na pierwszy argument wejściowy, a następnie wykombinować 'A' z' foo '. Następnie oba parametry szablonu są określane nawet w drugim przypadku. – kirakun

+1

@Kirakun niezupełnie. "A" i "B" można określić tylko wtedy, gdy określisz typ w '<>' lub wszystkie, które nie są określone w '<>' są na liście parametrów, więc kompilator może wydedukować wpisz z połączenia. W drugim przypadku '' 'nie jest jawnie określone w' <> 'ani nie jest na liście parametrów, więc nie może być znane. –

+1

@Kirakun tylko dlatego, że umieścisz go na liście parametrów, nie oznacza, że ​​jest pomijany, gdy zaczynasz wstawiać rzeczy między '<>'. Nadal są w takiej kolejności, w jakiej znajdują się na liście 'szablon ', więc 'B' jest pierwszy, a następnie' A' sekunda, zawsze, niezależnie od argumentów, które funkcja przyjmuje. –

Powiązane problemy