根据返回值重载C ++函数

时间:2008-10-22 15:02:01

标签: c++ function puzzle overloading

我们都知道您可以根据参数重载函数:

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之间,无需验证输入或进行任何错误处理。

17 个答案:

答案 0 :(得分:50)

您必须告诉编译器使用哪个版本。在C ++中,您可以通过三种方式完成。

通过键入

明确区分呼叫

你有点作弊,因为你向一个等待char的函数发送了一个整数,当char值'6'不是6但是54(用ASCII)时错误地发送了数字6:

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"

通过模板化返回值

来明确区分调用

使用这个解决方案,我们创建一个“虚拟”函数,其代码在实例化时不会编译:

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 ++ ......

: - P

答案 1 :(得分:41)

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 :(得分:23)

如果你想让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;
}

答案 3 :(得分:20)

没有

您不能通过返回值重载,因为调用者可以对其执行任何操作(或不执行任何操作)。考虑:

mul(1, 2);

返回值刚被丢弃,因此无法单独根据返回值选择重载。

答案 4 :(得分:8)

在类之间使用隐式转换。

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

BadIdea mul(int, int)

你明白这个主意,但是很明白。

答案 5 :(得分:4)

让mul成为一个类,mul(x,y)是它的构造函数,并重载一些转换操作符。

答案 6 :(得分:3)

您不能仅基于返回值重载函数。

但是,严格来说,这不是一个重载函数,你可以从函数返回一个重载转换运算符的类的实例。

答案 7 :(得分:2)

我认为你可以让它返回一些奇怪的类型Foo,只捕获参数然后Foo有一个隐式的运算符int和运算符字符串,它会“工作”,虽然它不会真正重载,而是隐含转换技巧。

答案 8 :(得分:1)

嗯,以下code project article似乎就是你所追求的。一定是魔术;)

答案 9 :(得分:1)

简短而简单,答案是否定的。在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);

答案 10 :(得分:0)

不在C ++中。你在上面的例子中得到的是返回的值,它是string可以理解的int转换,很可能是char。这将是ASCII 18或“设备控制2”。

答案 11 :(得分:0)

据我所知,你不能(很可惜,虽然......)。作为一种变通方法,您可以改为定义'out'参数,并重载该参数。

答案 12 :(得分:0)

您可以使用上面的仿函数解决方案。 C ++不支持除const之外的函数。您可以基于const重载。

答案 13 :(得分:-1)

您可以执行类似

的操作
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);

返回值无法重载。

答案 14 :(得分:-1)

将它放在不同的命名空间中?那就是我会这样做的。不是严格意义上的重载,而只是具有两个具有相同名称但具有不同范围的方法(因此:: scope resolution运算符)。

所以stringnamespace :: mul和intnamespace :: mul。也许它不是你所要求的,但它似乎是唯一的方法。

答案 15 :(得分:-1)

您可以使用模板,但是在拨打电话时必须指定模板参数。

答案 16 :(得分:-1)

好的天才;)这就是你如何做到这一点。


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

没有愚蠢的&lt;&gt;