Przeciążenie funkcji C++ zgodnie z wartością zwracaną

Wszyscy wiemy, że można przeciążać funkcję zgodnie z parametrami:

int mul(int i, int j) { return i*j; }
std::string mul(char c, int n) { return std::string(n, c); } 

Czy można przeciążać funkcję zgodnie z wartością zwracaną? Zdefiniuj funkcję, która zwraca różne rzeczy zgodnie z tym, jak używana jest zwracana wartość:

int n = mul(6, 3); // n = 18
std::string s = mul(6, 3); // s = "666"
// Note that both invocations take the exact same parameters (same types)

Można założyć, że pierwszy parametr mieści się w przedziale 0-9, nie ma potrzeby weryfikacji danych wejściowych ani obsługi błędów.

Author: Lightness Races in Orbit, 2008-10-22

17 answers

class mul
{
public:
    mul(int p1, int p2)
    {
        param1 = p1;
        param2 = p2;
    }
    operator int ()
    {
        return param1 * param2;
    }

    operator std::string ()
    {
        return std::string(param2, param1 + '0');
    }

private:
    int param1;
    int param2;
};
Nie żebym tego używał.
 41
Author: Coincoin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-05 08:50:53

Musisz powiedzieć kompilatorowi, której wersji użyć. W C++ można to zrobić na trzy sposoby.

Jawnie różnicuj wywołania wpisując

Trochę oszukałeś, ponieważ wysłałeś liczbę całkowitą do funkcji oczekującej na znak i błędnie wysłałeś liczbę 6, Gdy wartość znaku ' 6 ' nie jest 6, ale 54 (W ASCII):

std::string mul(char c, int n) { return std::string(n, c); }

std::string s = mul(6, 3); // s = "666"

Właściwym rozwiązaniem byłoby, oczywiście,

std::string s = mul(static_cast<char>(54), 3); // s = "666"

To było warte wspomnienia, myślę, nawet jeśli nie chcesz rozwiązanie.

Jawnie różnicuj wywołania za pomocą atrapy wskaźnika

Możesz dodać atrapę do każdej funkcji, zmuszając kompilator do wyboru właściwych funkcji. Najprostszym sposobem jest wysłanie atramentowego wskaźnika null typu pożądanego dla powrotu:

int mul(int *, int i, int j) { return i*j; }
std::string mul(std::string *, char c, int n) { return std::string(n, c); }

, który może być użyty z kodem:

int n = mul((int *) NULL, 6, 3); // n = 18
std::string s = mul((std::string *) NULL, 54, 3); // s = "666"

Jawnie różnicuj wywołania przez szablon zwracanej wartości

Dzięki temu rozwiązaniu tworzymy funkcję" atrapa " z kodem, który nie skompiluje się, jeśli utworzono instancję:

template<typename T>
T mul(int i, int j)
{
   // If you get a compile error, it's because you did not use
   // one of the authorized template specializations
   const int k = 25 ; k = 36 ;
}

Zauważ, że ta funkcja nie będzie się kompilować, co jest dobrą rzeczą, ponieważ chcemy używać tylko niektórych ograniczonych funkcji poprzez specjalizację szablonu:

template<>
int mul<int>(int i, int j)
{
   return i * j ;
}

template<>
std::string mul<std::string>(int i, int j)
{
   return std::string(j, static_cast<char>(i)) ;
}

W ten sposób skompiluje się następujący kod:

int n = mul<int>(6, 3); // n = 18
std::string s = mul<std::string>(54, 3); // s = "666"

Ale ten nie:

short n2 = mul<short>(6, 3); // error: assignment of read-only variable ‘k’

Jawnie różnicuj wywołania przez szablon zwracanej wartości, 2

Hej, ty też oszukiwałeś!

Racja, użyłem tego samego parametry dla dwóch funkcji "przeciążonych". Ale zacząłeś oszukiwać(patrz wyżej)...

^_^

Mówiąc bardziej poważnie, jeśli potrzebujesz mieć różne parametry, będziesz musiał napisać więcej kodu, a następnie będziesz musiał jawnie używać właściwych typów podczas wywoływania funkcji, aby uniknąć niejednoznaczności:

// For "int, int" calls
template<typename T>
T mul(int i, int j)
{
   // If you get a compile error, it's because you did not use
   // one of the authorized template specializations
   const int k = 25 ; k = 36 ;
}

template<>
int mul<int>(int i, int j)
{
   return i * j ;
}

// For "char, int" calls
template<typename T>
T mul(char i, int j)
{
   // If you get a compile error, it's because you did not use
   // one of the authorized template specializations
   const int k = 25 ; k = 36 ;
}

template<>
std::string mul<std::string>(char i, int j)
{
   return std::string(j, (char) i) ;
}

I ten kod będzie używany jako taki:

int n = mul<int>(6, 3); // n = 18
std::string s = mul<std::string>('6', 3); // s = "666"

I następujący wiersz:

short n2 = mul<short>(6, 3); // n = 18

Nadal nie kompiluje.

Podsumowanie

I kocham C++...

:-P

 50
Author: paercebal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-17 01:51:32

Jeśli chcesz, aby mul było rzeczywistą funkcją zamiast klasą, możesz użyć klasy pośredniej:

class StringOrInt
{
public:
    StringOrInt(int p1, int p2)
    {
        param1 = p1;
        param2 = p2;
    }
    operator int ()
    {
        return param1 * param2;
    }

    operator std::string ()
    {
        return std::string(param2, param1 + '0');
    }

private:
    int param1;
    int param2;
};

StringOrInt mul(int p1, int p2)
{
    return StringOrInt(p1, p2);
}

To pozwala robić rzeczy takie jak przekazywanie mul jako funkcji do algorytmów std:

int main(int argc, char* argv[])
{
    vector<int> x;
    x.push_back(3);
    x.push_back(4);
    x.push_back(5);
    x.push_back(6);

    vector<int> intDest(x.size());
    transform(x.begin(), x.end(), intDest.begin(), bind1st(ptr_fun(&mul), 5));
    // print 15 20 25 30
    for (vector<int>::const_iterator i = intDest.begin(); i != intDest.end(); ++i)
        cout << *i << " ";
    cout << endl;

    vector<string> stringDest(x.size());
    transform(x.begin(), x.end(), stringDest.begin(), bind1st(ptr_fun(&mul), 5));
    // print 555 5555 55555 555555
    for (vector<string>::const_iterator i = stringDest.begin(); i != stringDest.end(); ++i)
        cout << *i << " ";
    cout << endl;

    return 0;
}
 23
Author: Eclipse,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-09 21:02:03

Nie.

Nie można przeciążać wartością zwracaną, ponieważ wywołujący może z nią zrobić wszystko (lub nic). Consider:

mul(1, 2);

Wartość zwracana jest po prostu odrzucana, więc nie ma możliwości wyboru przeciążenia na podstawie samej wartości zwracanej.

 20
Author: MrZebra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 15:05:46

Użyj niejawnej konwersji w klasie in between.

class BadIdea
{
  public:
    operator string() { return "silly"; }
    operator int() { return 15; }
};

BadIdea mul(int, int)
Masz pomysł, okropny pomysł.
 8
Author: Pieter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 15:13:31

Niech mul będzie klasą, mul (x, y) jej konstruktorem i przeciąży niektóre operatory odlewnicze.

 4
Author: Federico A. Ramponi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 15:19:32

Nie można przeciążać funkcji tylko na podstawie zwracanej wartości.

Jednakże, podczas gdy ściśle mówiąc nie jest to funkcja przeciążona, możesz zwrócić ze swojej funkcji instancję klasy, która przeciąża operatory konwersji.

 3
Author: Franci Penov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 15:06:17

Zakładam, że możesz zwrócić jakiś dziwny typ Foo, który przechwytuje parametry, a następnie Foo ma implicit Operator int i operator string, i to "zadziała", choć tak naprawdę nie byłoby przeciążenia, a raczej ukrytą sztuczkę konwersji.

 2
Author: Brian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 15:15:11

Hmmm, poniższy artykuł code project wydaje się robić to, czego szukasz. Must be magic;)

 1
Author: Shane MacLaughlin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 15:13:15

Krótko i prosto, odpowiedź brzmi nie. W C++ wymagania są następujące:

1: Nazwa funkcji musi być taka sama
2: zbiór argumentów musi się różnić
* Typ powrotu może być taki sam lub inny

//This is not valid
    int foo();
    float foo();

    typedef int Int;

    int foo(int j);
    int foo(Int j);

//Valid:
   int foo(int j);
   char* foo(char * s);
   int foo(int j, int k);
   float foo(int j, float k);
   float foo(float j, float k);
 1
Author: John Littleberry Sr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-20 20:36:41

Z tego co wiem, to nie możesz (wielka szkoda...). Jako obejście można zamiast tego zdefiniować parametr " out " i przeciążyć go.

 0
Author: xtofl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 15:04:32

Nie w C++. W powyższym przykładzie otrzymałbyś zwracaną wartość, która jest int rzuconym w coś, co string może zrozumieć, najprawdopodobniej char. Czyli ASCII 18 lub "device control 2".

 0
Author: warren,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 15:08:33

Możesz użyć powyższego rozwiązania functora. C++ nie obsługuje tego dla funkcji z wyjątkiem const. Możesz przeciążać na podstawie const.

 0
Author: mempko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 15:48:56

Możesz użyć szablonu, ale wtedy będziesz musiał podać parametr szablonu podczas wykonywania połączenia.

 -1
Author: Joel Coehoorn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 15:05:59

Umieścić go w innej przestrzeni nazw? Tak bym to zrobił. Nie jest to stricte przeciążenie, raczej posiadanie dwóch metod o tej samej nazwie, ale o innym zakresie (stąd operator:: Scope resolution).

Więc stringnamespace::mul i intnamespace:: mul. Może to nie jest to, o co prosisz, ale wydaje się, że to jedyny sposób, aby to zrobić.

 -1
Author: AshtonKJ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 15:06:09

Mógłbyś zrobić coś takiego

template<typename T>
T mul(int i,int j){
    return i * j;
}

template<>
std::string mul(int i,int j){
    return std::string(j,i);
}

A potem nazwij to tak:

int x = mul<int>(2,3);
std::string s = mul<std::string>(2,3);

Nie ma możliwości przeciążenia wartości zwracanej.

 -1
Author: Paolo Tedesco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 15:11:05

OK geniusze;) tak to robicie jak zawodowcy.


class mul
{
 int m_i,m_j;
public:
 mull(int i,int j):m_i(i),m_j(j){}
 template
 operator R() 
 {
  return (R)m_i * m_j;
 }
};

Użyj jak


double d = mul(1,2);
long l = mul(1,2);

No stupid

 -1
Author: justin romaine,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-14 05:05:37