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

Posted

技术标签:

【中文标题】根据返回值重载一个C++函数【英文标题】:Overload a C++ function according to the return value 【发布时间】:2010-09-18 13:49:02 【问题描述】:

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

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

【问题讨论】:

嗯,以下code project article 似乎可以满足您的需求。一定是魔法;) 我希望这是可能的。我曾遇到过几个本可以使用它来简化代码的情况...... @Brian - 效果是可能的。请参阅下面的答案。 但是仅仅因为你可以......并不意味着你应该。 :) 很高兴给某人带来困难...... 这里只发生了隐式转换,没有发生重载 【参考方案1】:

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

通过键入明确区分调用

您有点作弊,因为您向等待字符的函数发送了一个整数,并且当 '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

【讨论】:

我很伤心。从好的方面来说,它既聪明又准确。不利的一面是,它是一把上膛的枪。 @jrodman : 请您详细说明一下“上膛枪”的技术输入,好吗?我看不出我在这个答案中写的任何内容(虚拟指针或模板化返回值)是如何反对语言的。 @jrodman:C++ 本身就是一把上膛的枪。这就是我们如此热爱它的原因:)【参考方案2】:
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;
;

我不会用那个。

【讨论】:

您可以添加转换函数,如operator identity&lt;int(*)()&gt;::type() return &amp;operator int; ,它允许将其传递给采用int(*)() 的函数,如果调用函数指针,则调用operator int 函数。【参考方案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 作为函数传递给标准算法:

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 和运算符 string,它会“工作”,尽管它不会真正重载,而是一个隐式转换技巧。

【讨论】:

【参考方案9】:

简而言之,答案是否定的。在 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】:

据我所知,你不能(可惜……)。作为一种解决方法,您可以改为定义一个“out”参数,然后重载该参数。

【讨论】:

【参考方案11】:

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

【讨论】:

【参考方案12】:

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

【讨论】:

【参考方案13】:

您可以使用模板,但您必须在调用时指定模板参数。

【讨论】:

【参考方案14】:

把它放在不同的命名空间?我会这样做。严格来说不是重载,而是只有两个具有相同名称但范围不同的方法(因此是 :: 范围解析运算符)。

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

【讨论】:

【参考方案15】:

你可以做类似的事情

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

没有办法重载返回值。

【讨论】:

【参考方案16】:

好的,天才们;)这就是你像专业人士一样做的事情。

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

不傻

【讨论】:

以上是关于根据返回值重载一个C++函数的主要内容,如果未能解决你的问题,请参考以下文章

C++:仅根据函数返回值类型不能实现重载

c++重载赋值操作符的返回值是啥?

C++运算符重载

c++核心编程--函数的重载

虚函数与重载函数的区别

c++部分面试题