Vraag Functieoverbelasting in C ++ door argumenten door te geven op waarde of op verwijzing


Als we deze voorbeeldfunctiescode hebben in C ++

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

Is het mogelijk om te verschillen in welke functie het oproepen van een wijziging in de aanroepende argumenten wordt genoemd?

Als de functie foo op een aantal van deze manieren wordt aangeroepen:

foo( 10);

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

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

het wordt de eerste foo overbelaste functie genoemd, omdat het geen const-argument kan doorverwijzen naar een niet-const-parameter. Maar hoe zou je de tweede foo-overbelastingsfunctie aanroepen? Als ik de volgende manier roep:

int i = 10;
foo( i);

Het gebeurt een dubbelzinnige fout omdat beide functies geldig zijn voor dit argument.

In deze link https://stackoverflow.com/a/5465379/6717386 het wordt uitgelegd als een manier om het op te lossen: het gebruik van objecten in plaats van ingebouwde typen en het privé doen van de kopieconstructor, zodat het geen kopie van de objectwaarde kan doen en het de tweede foo-overbelastingsfunctie moet worden genoemd en het object doorgeven referentie. Maar is er een manier met de ingebouwde typen? Ik moet de naam van de functie wijzigen om overbelasting te voorkomen?


10
2017-08-15 14:53


oorsprong


antwoorden:


U kunt een cast (van de functie) doen om de overbelastingsfunctie te selecteren:

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

demonstratie


12
2017-08-15 15:03



In de meeste gevallen omvat functieoverbelasting verschillende parametertypen en verschillende invoerparameters.

Uw poging is over het algemeen een slechte gewoonte en de resulterende gecompileerde code is afhankelijk van de compiler en code-optimalisatie kan de zaken zelfs nog verergeren.

U mag overwegen eenvoudigweg een tweede parameter toevoegen aan de tweede methode, iets als dit:

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

waar ... zou een booleaans type kunnen zijn, zeg: bool anotherFunction

Dus bellen foo(param1, param2) zou gewoon de tweede code bellen en iedereen is in orde.


4
2017-08-15 15:52



Zeer vreemd ontwerp, maar als je wilt ... Ik zal een oplossing aanbieden die even vreemd is als je ontwerp Gebruik Xreference in functiehandtekening. Vervolgens kunt u in de functie controleren wat u moet doen std::is_lvalue_reference, std::is_rvalue_reference.
Iets zoals dit

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
}

4
2017-08-15 16:03



Ondanks het goede antwoord van @ Jarod42, kunt u als een alternatieve oplossing vertrouwen op een sjabloondoorgangspunt en de overbelasting van een interne functie (als u niet wilt omgaan met expliciete afgietsels, natuurlijk).
Het volgt een minimaal, werkend voorbeeld:

#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);
}

De static_assert dient om de parameter te controleren als iets dat erbij hoort int (dat is int, int &, const int &, int && `, enzovoort).

Zoals je kunt zien aan de bovenstaande code, foo(i) zal afdrukken:

foo (int &)

Zoals verwacht.


2
2017-08-15 16:00



Nog een:

#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&)
}

1
2017-08-16 02:53