40

パラメータに従って関数をオーバーロードできることは誰もが知っています。

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 の間であると想定できます。入力を検証したり、エラー処理を行ったりする必要はありません。

4

16 に答える 16

55

使用するバージョンをコンパイラに指示する必要があります。C ++では、3つの方法で実行できます。

次のように入力して、呼び出しを明示的に区別します

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"

もちろん、正しい解決策は、

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をテンプレート化することにより、呼び出しを明示的に区別します。

ねえ、あなたもだましました!

そうです、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

于 2008-10-23T08:17:38.520 に答える
46
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;
};

私がそれを使うというわけではありません。

于 2008-10-22T15:18:16.893 に答える
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;
}
于 2009-01-09T21:02:03.143 に答える
21

いいえ。

呼び出し元は何でもできる (または何もできない) ため、戻り値でオーバーロードすることはできません。検討:

mul(1, 2);

戻り値は破棄されるだけなので、戻り値だけに基づいてオーバーロードを選択する方法はありません。

于 2008-10-22T15:05:46.543 に答える
8

中間クラスで暗黙的な変換を使用します。

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

BadIdea mul(int, int)

あなたはその考えを理解します、しかしひどい考えです。

于 2008-10-22T15:13:31.253 に答える
4

mul をクラス、mul(x, y) をそのコンストラクタとし、いくつかのキャスト演算子をオーバーロードします。

于 2008-10-22T15:19:32.270 に答える
3

戻り値のみに基づいて関数をオーバーロードすることはできません。

ただし、厳密に言えば、これはオーバーロードされた関数ではありませんが、変換演算子をオーバーロードするクラスのインスタンスの結果として、関数から返すことができます。

于 2008-10-22T15:06:17.947 に答える
2

パラメータをキャプチャするだけの奇妙な型 Foo を返すことができ、Foo には暗黙的な演算子 int と演算子文字列があり、実際にはオーバーロードではなく、暗黙的な変換トリックではなく、「機能する」と思います。

于 2008-10-22T15:15:11.563 に答える
2

簡潔に言うと、答えは NO です。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);
于 2011-07-19T22:06:34.370 に答える
0

私の知る限り、できません(残念ながら...)。回避策として、代わりに「out」パラメーターを定義し、それをオーバーロードすることができます。

于 2008-10-22T15:04:32.397 に答える
0

C++ にはありません。上記の例で得られるのは、返される値です。これは、理解できる何かにキャストされた int であり、stringおそらくchar. どちらがASCII 18または「デバイスコントロール2」になります。

于 2008-10-22T15:08:33.010 に答える
0

上記のファンクター ソリューションを使用できます。C++ は、const 以外の関数ではこれをサポートしていません。const に基づいてオーバーロードできます。

于 2008-10-22T15:48:56.707 に答える
-1

テンプレートを使用することもできますが、呼び出しを行うときにテンプレート パラメーターを指定する必要があります。

于 2008-10-22T15:05:59.193 に答える
-1

OK、あなたは天才です ;) これがプロのように行う方法です。


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

ばかじゃない <>

于 2010-05-14T05:05:37.393 に答える
-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);

戻り値をオーバーロードする方法はありません。

于 2008-10-22T15:11:05.190 に答える
-1

別の名前空間に配置しますか? それは私がそれを行う方法です。厳密にはオーバーロードではなく、名前が同じでスコープが異なる 2 つのメソッドがあるだけです (したがって :: スコープ解決演算子)。

つまり、stringnamespace::mul と intnamespace::mul です。多分それはあなたが求めているものではないかもしれませんが、それを行う唯一の方法のようです.

于 2008-10-22T15:06:09.757 に答える