2017-01-01 7 views
0

「関数受信値」(#A)よりも「関数受信参照」(#B)を優先する方法を教えてください。あいまい:f(A&)オーバーロードの優先度をf(A)

#include <iostream> 
using namespace std; 

class Heavy{/* ...... */}; //a complex class 
Heavy generateHeavy(){ 
    return Heavy(); 
} 
void f(Heavy x){ //#A I want LOW priority. 
    std::cout<<"case 1: pass by value"<<std::endl; 
} 
void f(Heavy& x){ //#B I want HIGH priority. (save CPU for big object) 
    std::cout<<"case 2: pass by reference"<<std::endl; 
} 

int main() { 
    //vvvv Here is existing code base that I don't want to touch. 
    f(generateHeavy()); //compiler call case 1 -> ok (I prefer reference, though) 
    Heavy heavy; 
    f(heavy); //should call case 2, but compiler fail (ambiguous) <= question 
    return 0; 
} 

この問題は、SFINAEを可能な限り参照渡しが望ましい実際のケースに拡張しようとする最初の試みから来ています。

+1

「Heavy」オーバーロードを「Heavy &&」で置き換える必要があります。 – StoryTeller

+0

@StoryTeller良い点。したがって、(時々)それを使用するときstd :: move()を呼び出さなければなりませんか?申し訳ありませんが、私は言及を忘れて、私は多くの既存のコードベースに触れたくありません。 – javaLover

+0

必ずしもそうではありません。また、Heavy(existing_heavy)というコピーで呼び出すこともできます。全体のポイントは、デフォルトでコピーを作成しないようにすることです。 – StoryTeller

答えて

2

あなたが尋ねたとして文字通り行う方法は

template <typename T = void> 
std::enable_if_t<std::is_same<T, void>::value> f(Heavy x) { ... } 

void f(Heavy& x) { ... } 

最初は関数テンプレートであるが、唯一のT = voidが許可されます。第二はありません。他のすべてが等しい場合は、非テンプレートがテンプレートよりも優先されます。


今、実際のコードでは、これを実行しない可能性があります。あなたはサポートしたいコールを見て、それらのコールに適したより適切なアプローチを見つけます。 @StoryTellerは&&を提案:

void f(Heavy &&) { ... } 
void f(Heavy &) { ... } 

あなたがそのようなあなたの関数の結果として右辺値を、持っているとき、Heavy &&過負荷が呼び出されることを意味しています。これは通常、罰金だが、それは正確にあなたが尋ねたものと同じではないことに注意してください:あなたはこの呼び出しf(Heavy)になるだろうを求めて何

const Heavy c; 
f(c); 

。代わりに、Heavy &&の過負荷では、これを受け入れる過負荷はありません。

追加のオーバーロードvoid f(const Heavy &)がこれをカバーできます。この質問には、これがあなたのユースケースの適切なアプローチであるかどうかを知るための十分な情報はありませんが、それはあなた自身を把握できるはずのものです。

+0

私が使っている場合'f(Heavy &&)'と 'f(Heavy&)'では、重いコピーはありませんよね?どちらの場合もコピーがなければ、私が望んでいたほうが良いでしょう。 XD(ライブ・コードの場合はhttps://ideone.com/xzb8F0) – javaLover

+1

@javaLoverどちらのオーバーロードも参照を取るため、いずれかのオーバーロードへの呼び出しにコピーは含まれません。しかし、事実上、 '空きf(重い);重いg(); 'と' f(g()) 'のどちらもコピーを伴わなかった。厳密には保証されているわけではありませんが、 'f'のパラメータ用に予約されたメモリに' g'の結果を直接構築するために、複数のコンパイラが実際にそれを行います。 – hvd

関連する問題