根据返回值重载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); 

没有愚蠢的<>