2012-04-20 36 views
15

Obniżona przykładowy kod:szablony o zmiennej liczbie argumentów z 'const' parametrem przeciążenia

#include <iostream> 

template<typename T> 
void func(T &x) 
{ 
    std::cout << "non-const " << x << std::endl; 
} 

template<typename T> 
void func(const T &x) 
{ 
    std::cout << "const " << x << std::endl; 
} 

template<typename ...ARGS> 
void proxy(ARGS ...args) 
{ 
    func(args...); 
} 

int main() 
{ 
    int i = 3; 

    func(i); 
    func(5); 
    func("blah"); 

    proxy(i); 
    proxy(5); 
    proxy("blah"); 
} 

oczekiwany wynik:

non-const 3 
const 5 
const blah 
non-const 3 
const 5 
const blah 

Rzeczywista moc:

non-const 3 
const 5 
const blah 
non-const 3 
non-const 5 
non-const blah 

Więc jakoś const kwalifikator funkcji parametr zostanie utracony po przejściu przez szablon variadic. Czemu? Jak mogę temu zapobiec?

PS: testowane z GCC 4.5.1 i SUSE 11,4

+0

Nie ma to nic wspólnego z szablonami variadic. Twoje parametry proxy szablonu funkcji są nie-referencjami, więc stała argumentów funkcji jest ignorowana podczas dedukowania argumentów szablonu. – Cosyn

Odpowiedz

18

Po prostu natknąć się na forwarding problem. Ten problem został rozwiązany za pomocą perfect forwarding.

Zasadniczo trzeba zabrać swoje parametry przez rvalue odniesieniem, i polegać na std::forward poprawnie przekazuje je zachowując swój charakter:

template<typename ...Args> 
void proxy(Args&& ...args) 
{ 
    func(std::forward<Args>(args)...); 
} 
+0

Nie potrzebujesz 'std :: forward '? – juanchopanza

+0

@juanchopanza No. To by przekazało wszystkie argumenty typu do 'std :: forward', ale' std :: forward' ma tylko jeden argument typu. –

+0

@ R.MartinhoFernandes Right, forward również przyjmuje tylko jeden parametr, więc myślę, że potrzebujemy 'func (std :: forward (args) ...); "czy coś w tym stylu? próbka w odpowiedzi nie jest kompilowana na mojej migawce gcc4.7. – juanchopanza

6

Jak Luc już wspomniano jest to problem spedycji i odpowiedzi do jak temu zapobiec? jest użycie idealnego przekazywania. Ale postaram się odpowiedzieć na inne pytania na końcu:

W ten sposób kwalifikator const parametru funkcji zostaje utracony po przejściu przez szablon variadic. Czemu?

To wszystko ma związek z wnioskiem o typie. Ignorować, że używasz zmiennej liczbie argumentów szablony i rozważyć najprostszy szablon jeden argument:

template <typename T> 
void one_arg_proxy(T arg) { 
    func(arg); 
} 

w miejscu połączenia masz one_arg_proxy(5), czyli argumentem jest intRValue. Rodzaj wnioskowanie w rzutach, aby dowiedzieć się, co rodzaj T powinno być, a przepisy stanowią, że T jest int, więc rozmowa zostanie przetłumaczony na one_arg_proxy<int>(5) i konkretyzacji szablonu, który pobiera kompilowane jest:

template <> 
void one_arg_proxy<int>(int arg) { 
    func(arg); 
} 

Teraz wywołanie func przyjmuje argument o wartości o wartości, a zatem wersja func przyjmująca odwołanie o stanie innym niż const jest lepszym rozwiązaniem (nie wymaga żadnych konwersji) niż ten, który pobiera const&, uzyskując wynik, który otrzymujesz. Problem polega na tym, że func nie jest wywoływany z argumentem do proxy, ale raczej z wewnętrzną kopią wykonaną z tego proxy.

Powiązane problemy