根据返回值重载C ++函数
我们都知道你可以根据参数重载一个函数:
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之间,不需要validationinput或者有任何error handling。
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的函数,并且在'6'的char值不是6而是54(ASCII)时错误地发送了数字6:
std::string mul(char c, int n) { return std::string(n, c); } std::string s = mul(6, 3); // s = "666"
当然,正确的解决scheme是,
std::string s = mul(static_cast<char>(54), 3); // s = "666"
我猜这值得一提,即使你不想要这个解决scheme。
通过虚拟指针显式区分调用
您可以为每个函数添加一个虚拟参数,从而强制编译器select正确的函数。 最简单的方法是发送返回所需types的空虚拟指针:
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"
通过模板化返回值显式区分调用
通过这个解决scheme,我们创build了一个“虚拟”函数,其代码在实例化时不会被编译:
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通过模板化返回值显式区分调用2
嘿,你也骗了!
对,我为两个“超载”function使用了相同的参数。 但是你确实开始了作弊(见上文)。
^ _ ^
更严重的是,如果你需要有不同的参数,那么你将会编写更多的代码,然后在调用函数时必须明确地使用正确的types以避免含糊不清:
// 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 ++ …
😛
如果你想让一个真正的函数而不是一个类,你可以只使用一个中间类:
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
作为函数传递给stdalgorithm:
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);
返回值只是被丢弃,所以没有办法可以根据返回值单独select一个重载。
在类之间使用隐式转换。
class BadIdea { public: operator string() { return "silly"; } operator int() { return 15; } }; BadIdea mul(int, int)
你明白了,可怕的主意。
让mul成为一个类,mul(x,y)的构造函数,并重载一些铸造操作符。
只能根据返回值重载函数。
然而,严格来说,这不是一个重载函数,因此可以从函数返回一个重载转换运算符的类的实例。
我认为你可以让它返回一些奇怪的typesFoo,只是捕获参数,然后Foo有一个隐式操作符int和操作符string,它会“工作”,虽然它不会真的重载,而是一个隐式的转换技巧。
嗯,下面的代码项目文章似乎做了你以后。 一定是魔法;)
简而言之,答案是否定的。 在C ++中,要求是:
1:函数的名称必须相同
2:参数集必须不同
*返回types可以相同或不同
//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或“设备控制2”。
你可以使用上面的函子解决scheme。 除了const,C ++不支持这个函数。 你可以基于const重载。
你可以使用模板,但是当你打电话时你必须指定模板参数。
把它放在一个不同的命名空间? 那将是我将如何做到这一点。 不是严格的重载,而是只有两个同名的方法,但是有一个不同的作用域(因此:: scopeparsing运算符)。
所以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; } };
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);
没有愚蠢的<>