Перегрузите функцию C ++ в соответствии с возвращаемым значением
-
03-07-2019 - |
Вопрос
Мы все знаем, что вы можете перегрузить функцию в соответствии с параметрами:
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, нет необходимости проверять входные данные или выполнять какую-либо обработку ошибок.
Решение
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;
};
Не то чтобы я это использовал.
Другие советы
Вы должны указать компилятору, какую версию использовать.В C ++ вы можете сделать это тремя способами.
Явно различайте вызовы, набрав
Вы несколько схитрили, потому что отправили целое число в функцию, ожидающую 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"
Я думаю, об этом стоило упомянуть, даже если вам не нужно было это решение.
Явно различайте вызовы по фиктивному указателю
Вы можете добавить фиктивный параметр к каждой функции, тем самым вынудив компилятор выбирать правильные функции.Самый простой способ - отправить нулевой фиктивный указатель типа, желаемого для возврата:
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"
Явно различайте вызовы, задавая шаблон возвращаемого значения
С помощью этого решения мы создаем "фиктивную" функцию с кодом, который не будет компилироваться при создании экземпляра:
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 ;
}
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'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) ;
}
И этот код был бы использован как таковой:
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
Все равно не скомпилируется.
Заключение
Я люблю C ++...
:-п
Если вы хотите сделать 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);
}
Это позволяет вам передавать <=> как функцию в алгоритмы 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;
}
Нет.
Вы не можете перегружать по возвращаемому значению, потому что вызывающий может делать с ним все (или ничего).Рассмотреть:
mul(1, 2);
Возвращаемое значение просто выбрасывается, поэтому он никак не может выбрать перегрузку, основанную только на возвращаемом значении.
Используйте неявное преобразование в промежуточном классе.
class BadIdea
{
public:
operator string() { return "silly"; }
operator int() { return 15; }
};
BadIdea mul(int, int)
Вы поняли идею, хотя ужасная идея.
Пусть mul будет классом, mul (x, y) его конструктором и перегрузит некоторые операторы приведения.
Вы не можете перегрузить функцию только на основе возвращаемого значения.
Однако, строго говоря, это не перегруженная функция, в результате вы можете вернуть из своей функции экземпляр класса, который перегружает операторы преобразования.
Я полагаю, вы могли бы вернуть некий странный тип Foo, который просто захватывает параметры, и тогда у Foo есть неявный оператор int и строка оператора, и он будет " work " хотя это не будет ' это действительно перегрузка, скорее неявный трюк преобразования.
Хммм, следующая статья проекта кода , похоже, делает то, что вы есть после. Должно быть волшебство;)
Коротко и просто, ответ НЕТ. В C ++ следующие требования:
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);
Насколько я знаю, вы не можете (правда, очень жаль ...). В качестве обходного пути вы можете вместо этого определить параметр out и перегрузить его.
Не в C ++. В приведенном выше примере вы получите возвращаемое значение, представляющее собой int, преобразованное во что-то, что string
может понять, скорее всего, char
. Что будет ASCII 18 или & Quot; устройство управления 2 & Quot;.
Вы можете использовать решение функтора выше. C ++ не поддерживает это для функций, кроме const. Вы можете перегружать в зависимости от const. Р>
Вы можете использовать шаблон, но тогда вам нужно будет указать параметр шаблона при выполнении вызова.
Поместить его в другое пространство имен? Вот как бы я это сделал. Не просто перегрузка, а просто наличие двух методов с одинаковым именем, но с другой областью действия (отсюда и оператор разрешения области действия).
Итак, stringnamespace :: mul и intnamespace :: mul. Возможно, это не совсем то, о чем вы просите, но, похоже, это единственный способ сделать это.
Вы могли бы сделать что-то вроде
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);
Перегрузка возвращаемого значения невозможна.
ОК, вы, гении;) так вы и делаете, как профессионал.
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);
не глупо < >