Перегрузка функции С++ в соответствии с возвращаемым значением

Мы все знаем, что вы можете перегрузить функцию в соответствии с параметрами:

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

Можете ли вы перегрузить функцию в соответствии с возвращаемым значением? Определите функцию, которая возвращает разные вещи в соответствии с тем, как используется возвращаемое значение:

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)

Вы можете предположить, что первый параметр находится между 0-9, нет необходимости проверять ввод или обрабатывать ошибки.

Ответ 1

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

Не то, чтобы я использовал это.

Ответ 2

Вы должны сообщить компилятору, какую версию использовать. В С++ вы можете сделать это тремя способами.

Явно различать вызовы, набрав

Вы несколько обманули, потому что вы отправили целое число в функцию, ожидающую char, и ошибочно отправили номер шесть, когда значение char для "6" не 6, а 54 (в ASCII):

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

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

Правильное решение было бы, конечно,

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

Этого стоит упомянуть, я думаю, даже если вы не хотите решения.

Явно дифференцировать вызовы с помощью фиктивного указателя

Вы можете добавить фиктивный параметр для каждой функции, тем самым вынуждая компилятор выбирать правильные функции. Самый простой способ - отправить NULL фиктивный указатель типа, требуемого для возврата:

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

Что можно использовать с кодом:

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

Явно дифференцировать вызовы путем шаблонирования возвращаемого значения

С помощью этого решения мы создаем функцию "dummy" с кодом, который не будет компилироваться при создании экземпляра:

template<typename T>
T mul(int i, int j)
{
   // If you get a compile error, it 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 ;
}

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

Таким образом, следующий код будет скомпилирован:

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

Но этого не будет:

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

Явно дифференцировать вызовы путем шаблонирования возвращаемого значения, 2

Эй, ты тоже обманул!

Правильно, я использовал одни и те же параметры для двух "перегруженных" функций. Но вы начали обман (см. Выше)...

^ _ ^

Более серьезно, если вам нужно иметь разные параметры, тогда вы должны будете написать больше кода, а затем должны явно использовать правильные типы при вызове функций, чтобы избежать двусмысленностей:

// For "int, int" calls
template<typename T>
T mul(int i, int j)
{
   // If you get a compile error, it 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 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) ;
}

И этот код будет использоваться как таковой:

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

И следующая строка:

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

Не будет компилироваться.

Заключение

Я люблю С++...

: - р

Ответ 3

Если вы хотите сделать mul реальную функцию вместо класса, вы можете просто использовать промежуточный класс:

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

Это позволяет вам делать что-то вроде передачи mul как функции в 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;
}

Ответ 4

Нет.

Вы не можете перегрузить по возвращаемому значению, потому что вызывающий может делать с ним что-либо (или ничего). Рассмотрим:

mul(1, 2);

Возвращаемое значение просто выбрасывается, поэтому он не может выбрать перегрузку только на основе возвращаемого значения.

Ответ 5

Использовать неявное преобразование между классами.

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

BadIdea mul(int, int)

У вас есть идея, ужасная идея.

Ответ 6

Пусть mul - класс, mul (x, y) - его конструктор и перегружает некоторые операторы литья.

Ответ 7

Вы не можете перегружать функцию, основанную только на возвращаемом значении.

Однако, строго говоря, это не перегруженная функция, вы можете вернуться из своей функции в результате экземпляра класса, который перегружает операторы преобразования.

Ответ 8

Я предполагаю, что вы могли бы вернуть ему какой-то странный тип Foo, который просто захватывает параметры, а затем Foo имеет неявный оператор int и операторную строку, и он будет "работать", хотя на самом деле он не будет перегружать, а не подразумевается трюк преобразования.

Ответ 9

Hmmm, следующая статья проекта кода, кажется, делает то, что вы после. Должно быть волшебство;)

Ответ 10

Короче и просто, ответ НЕТ. В С++ требования:

1: имя функций ДОЛЖНО быть одинаковым
2: набор аргументов ДОЛЖЕН отличаться * Тип возврата может быть одним и тем же или другим

//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);

Ответ 11

Насколько я знаю, вы не можете (большая жалость, хотя...). В качестве обходного пути вы можете определить параметр "out" и перегрузить его.

Ответ 12

Не в С++. То, что вы получили в приведенном выше примере, будет возвращаемым значением, которое является int cast во что-то string, может понять, скорее всего, char. Это будет ASCII 18 или "устройство 2 управления".

Ответ 13

Вы можете использовать вышеприведенное решение. С++ не поддерживает это для функций, кроме const. Вы можете перегружать на основе const.

Ответ 14

Вы можете использовать шаблон, но тогда вам нужно будет указать параметр шаблона при выполнении вызова.

Ответ 15

Поместите его в другое пространство имен? Я бы это сделал. Не строго перегрузка, а просто наличие двух методов с тем же именем, но другая область действия (следовательно, оператор разрешения области видимости).

Итак, stringnamespace:: mul и intnamespace:: mul. Возможно, это не то, о чем вы просите, но это похоже на единственный способ сделать это.

Ответ 16

Вы можете сделать что-то вроде

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

И затем назовите его следующим образом:

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

Невозможно перегрузить возвращаемое значение.

Ответ 17

ОК, вы гении;) вот как вы делаете это как профессионал.


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

используйте как


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

нет глупости < >