パラメータに従って関数をオーバーロードできることは誰もが知っています。
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であり、入力を確認したり、エラー処理を行ったりする必要はないと想定できます。
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++では、3つの方法で実行できます。
文字を待機している関数に整数を送信し、「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
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;
}
番号。
呼び出し元は戻り値を使用して何でも(または何も)できないため、戻り値でオーバーロードすることはできません。考えてみましょう:
mul(1, 2);
戻り値は破棄されるだけなので、戻り値だけに基づいてオーバーロードを選択する方法はありません。
クラス間の暗黙的な変換を使用します。
class BadIdea
{
public:
operator string() { return "silly"; }
operator int() { return 15; }
};
BadIdea mul(int, int)
しかし、あなたはその考え、ひどい考えを得る。
Mulをクラス、mul(x、y)をそのコンストラクターとし、いくつかのキャスト演算子をオーバーロードします。
戻り値のみに基づいて関数をオーバーロードすることはできません。
ただし、厳密に言えば、これはオーバーロードされた関数ではありませんが、変換演算子をオーバーロードするクラスのインスタンスの結果として、関数から戻る可能性があります。
パラメータをキャプチャするだけの奇妙なタイプのFooを返すことができ、Fooには暗黙の演算子intと演算子文字列があり、実際にはオーバーロードではなく、暗黙の変換トリックではありますが、「機能」すると思います。
短くて単純な答えは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);
うーん、次の コードプロジェクトの記事 はあなたが求めていることをしているようです。魔法でなければなりません;)
上記のファンクターソリューションを使用できます。 C++は、const以外の関数ではこれをサポートしていません。 constに基づいてオーバーロードできます。
私の知る限り、あなたはできません(しかし、大きな残念です...)。回避策として、代わりに「out」パラメーターを定義し、そのパラメーターをオーバーロードすることができます。
C++ではありません。上記の例で得られるのは、string
が理解できるもの、おそらくchar
にキャストされたintである戻り値です。 ASCII 18または "デバイス制御2"になります。