戻り値に従ってC ++関数をオーバーロードします
-
03-07-2019 - |
質問
パラメータに従って関数をオーバーロードできることは誰もが知っています:
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つの方法で実行できます。
入力して呼び出しを明示的に区別する
charを待機している関数に整数を送信し、「6」のchar値が6ではなく54(ASCIIの場合)である場合、誤って数字6を送信したため、ややcheされました:
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"
戻り値をテンプレート化することにより、呼び出しを明示的に区別します
このソリューションでは、<!> quot; dummy <!> quot;を作成します。インスタンス化されてもコンパイルされないコードを含む関数:
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つの<!> quot; overloaded <!> quot;に同じパラメーターを使用しました。関数。しかし、不正行為を開始しました(上記を参照)...
^ _ ^
さらに深刻なのは、異なるパラメーターが必要な場合は、さらにコードを記述し、曖昧さを避けるために関数を呼び出すときに適切な型を明示的に使用する必要があることです。
// 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);
}
これにより、<=>を関数として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と演算子文字列があり、<!> quot; work <!> quot;になりますが、 tは実際にはオーバーロードであり、むしろ暗黙的な変換のトリックです。
ふむ後。魔法でなければなりません;)
短くて簡単な、答えは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);
私が知る限り、あなたはできません(しかし、残念です...)。回避策として、代わりに「out」パラメーターを定義し、そのパラメーターをオーバーロードできます。
C ++ではありません。上記の例で得られるのは、string
が理解できるもの、おそらくchar
にキャストされるintである戻り値です。 ASCII 18または<!> quot; device control 2 <!> quot;です。
上記のファンクターソリューションを使用できます。 C ++は、const以外の関数ではこれをサポートしていません。 constに基づいてオーバーロードできます。
テンプレートを使用できますが、呼び出し時にテンプレートパラメータを指定する必要があります。
別のネームスペースに配置しますか?それは私がそれをする方法です。厳密にはオーバーロードではなく、同じ名前の2つのメソッドだけで、スコープが異なります(したがって::スコープ解決演算子)。
つまり、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);
戻り値をオーバーロードする方法はありません。
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);
愚かな<!> lt; <!> gt;