2016-08-15 10 views
9

Jeśli mamy ten przykładowy kod funkcji w C++Funkcja przeciążenia w C++ argumentów przechodzących przez wartość lub przez odwołanie

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

Czy możliwe jest różnicą jaką funkcję zadzwonić robić żadnych zmian w argumentach dzwoni?

Jeśli foo funkcja nazywa się w niektórych z tych sposobów:

foo(10); 

i = 10; 
foo(static_cast<const int>(i)); 

foo(static_cast<const int&>(i)); 

to się nazywa pierwszy foo przeciążony funkcję, ponieważ nie może przechodzić przez odniesienie const argument const parametru. Ale jak możesz zadzwonić do drugiej funkcji przeciążenia foo? Gdybym wywołać następny sposób:

int i = 10; 
foo(i); 

Zdarza niejednoznaczne błąd, ponieważ obie funkcje są ważne dla tego argumentu.

W tym linku https://stackoverflow.com/a/5465379/6717386 wyjaśniono, w jaki sposób można go rozwiązać: używając obiektów zamiast wbudowanych typów i wykonując prywatny konstruktor kopiowania, więc nie można wykonać kopii wartości obiektu i należy go nazwać drugim foo przeciążenie i przekazanie obiektu przez odniesienie. Ale czy istnieje jakiś sposób z wbudowanymi typami? Muszę zmienić nazwę funkcji, aby uniknąć przeciążenia?

+1

Próbowałaś 'foo (static_cast (i));' – mvidelgauz

+1

można użyć 'void foo (int x)' i 'void foo (? int * x) 'zamiast. – DimChtz

+0

@mvidelgauz Tak, próbowałem tego samego błędu niż powyżej. :( –

Odpowiedz

11

Można zrobić odlew (funkcji), aby wybrać funkcję przeciążeniem:

static_cast<void (&)(int&)>(foo)(i); 

Demo

+0

Dzięki, działa dobrze!. Ale próbuję twojego rozwiązania z klasami i metodami i pojawia się błąd _error: invalid static_cast z typu '' do typu 'void (&) (Punto &)' _. To [tutaj link:] (http://ideone.com/ZxrqOt) –

+1

@CarlosUrda Musisz podać nazwę klasy w wskaźniku metody, np. static_cast (& MyClass :: foo); – Resurrection

+1

@ CarlosUrda: Składnia jest jeszcze brzydsza, zobacz [Demo] (http://coliru.stacked-crooked.com/a/e83fc0f4e3e76603). – Jarod42

4

W większości instancji, funkcja przeciążenia obejmuje różne typy parametrów i różnych długościach parametrów wejściowych.

Twoja próba jest ogólnie złą praktyką, a wynikowy skompilowany kod zależy od kompilatora, a optymalizacja kodu może nawet pogorszyć sytuację.

Można rozważyć prostu dodanie drugiego parametru do drugiego sposobu, coś takiego:

void foo(int x) { std::cout << "foo(int)" << std::endl; } 
void foo(int& x, ...) { std::cout << "foo(int &, ...)" << std::endl; } 

gdzie ... może być typu boolean, powiedzieć: bool anotherFunction

Więc wywołanie foo(param1, param2) po prostu zadzwoń do drugiego kodu i wszyscy są w porządku.

+1

Zależnie od kompilatora? O ile kompilator nie jest zepsuty, nie ma powodu, aby zmienić jego zachowanie .. – Quentin

+1

Dzięki, ale nie podoba mi się twoje rozwiązanie Próbuję użyć tej samej nazwy funkcji dla settera pobierającego w klasie 'klasa Circulo { \t publiczny: \t \t void centro (const Punto &); // seter \t \t void centro (Punto &) const; // getter \t private: \t \t Punto centro_; }; ' –

+1

Przepraszamy, ale pytanie nie było wystarczająco wyraźne. Po prostu uważam, że utrzymanie prostych rzeczy jest kluczowe. Jednakże, jeśli chodzi o pobierający i ustawiający, dla bardziej czytelnego kodu, można rozważyć NIE używanie parametrów dla swoich pobierających. Wciąż będziesz zapobiegał temu błędowi, jeśli zastosujesz się do tego podejścia, a Twój kod będzie nadal bardzo czysty. –

2

Pomimo dobrej odpowiedzi @ Jarod42, jako alternatywne rozwiązanie można polegać na szablonowym punkcie wejścia i przeciążeniu funkcji wewnętrznej (oczywiście jeśli nie chcemy zajmować się jawnymi rzutami).
Wynika minimalny, przykład pracy:

#include<type_traits> 
#include<iostream> 
#include<utility> 

void foo_i(char, int x) { std::cout << "foo(int)" << std::endl; } 
void foo_i(int, int &x) { std::cout << "foo(int &)" << std::endl; } 

template<typename T> 
void foo(T &&t) { 
    static_assert(std::is_same<std::decay_t<T>, int>::value, "!"); 
    foo_i(0, std::forward<T>(t)); 
} 

int main() { 
    foo(10); 
    int i = 10; 
    foo(static_cast<const int>(i)); 
    foo(static_cast<const int &>(i)); 
    foo(i); 
} 

static_assert służy do sprawdzania parametru być coś, co wiąże int (czyli int, int &, const int &, int & & `, i tak dalej) .

Jak widać z powyższego kodu, foo(i) wypisze:

foo(int &)

jak oczekiwano.

4

Bardzo dziwny projekt, ale jeśli chcesz ... Zaproponuję rozwiązanie tak dziwne, jak twój projekt. Użyj Xreference w sygnaturze funkcji. Następnie w funkcji możesz sprawdzić, co musisz zrobić, używając std::is_lvalue_reference, std::is_rvalue_reference.
coś takiego

template<class T> 
void foo(T&& x) 
{ 
    static_assert(std::is_same<std::decay_t<T>, int>::value, "!"); 
    if (std::is_rvalue_reference<T&&>::value) 
    std::cout << "do here what you want in foo(int x)"; 
    else 
    std::cout << "do here what you want in foo(int & x)"; 
} 

int main() 
{ 
    int x = 5; 
    foo(x); //"do here what you want in foo(int x)" - will be printed 
    foo(std::move(x)); //"do here what you want in foo(int & x)" - will be printed 
} 
1

Inny:

#include <iostream> 
#include <functional> 

void foo(int x) 
{ 
    std::cout << "foo(int)\n"; 
} 

template<typename T> 
void foo(T&& x) 
{ 
    std::cout << "foo(int&)\n"; 
} 

int main() 
{ 
    int i = 10; 
    foo(i);   // foo(int) 
    foo(std::ref(i)); // foo(int&) 
} 
+0

złe rozwiązanie. Ogólnie nie jest dobrym pomysłem na przeciążanie funkcji, których jedynym argumentem jest Xreference. Na przykład: const int i = 10; foo (i); wyświetli "foo (int &) \ n" –

+0

@AndreyNekrasov Cóż, być może inne złe rozwiązanie, ale 'const int i = 10; foo (i); 'wypisuje foo (int) w moim gcc. – Loreto

Powiązane problemy