C++11 より前は、次のようなコードを書いていました。
// Small functions
void doThingsWithA(const A& a)
{
// do stuff
}
void doThingsWithB(const B& b)
{
// do stuff
}
void doThingsWithC(const C& c)
{
// do stuff
}
// Big function
void doThingsWithABC(const A& a, const B& b, const C& c)
{
// do stuff
doThingsWithA(a);
doThingsWithB(b);
doThingsWithC(c);
// do stuff
}
しかし、移動セマンティクスを使用すると、(少なくとも場合によっては) 関数が右辺値参照をパラメーターとして取り、これらのオーバーロードを追加できるようになる可能性があります。
void doThingsWithA(A&& a);
void doThingsWithB(B&& b);
void doThingsWithC(C&& c);
私が集めたものから、大きな関数内でこれらのオーバーロードを呼び出せるようにしたい場合は、次のように見える完全な転送を使用する必要があります (少し読みにくいですが、テンプレート タイプの適切な命名規則):
template<typename TplA, typename TplB, typename TplC>
void doThingsWithABC(TplA&& a, TplB&& b, TplC&& c)
{
// do stuff
doThingsWithA(std::forward<TplA>(a));
doThingsWithB(std::forward<TplB>(b));
doThingsWithC(std::forward<TplC>(c));
// do stuff
}
私の問題はこれです:私の小さな関数に他のオーバーロードがある場合、意図されていない型のパラメーターを使用して大きな関数を呼び出すことが可能になるということではありませんか?
これを防ぐためにこれが機能する可能性があると思います:
template<typename TplA, typename TplB, typename TplC,
class = typename std::enable_if<std::is_same<A, std::decay<TplA>::type>::value>::type,
class = typename std::enable_if<std::is_same<B, std::decay<TplB>::type>::value>::type,
class = typename std::enable_if<std::is_same<C, std::decay<TplC>::type>::value>::type>
doThingsWithABC(TplA&& a, TplB&& b, TplC&& c)
{
// do stuff
doThingsWithA(std::forward<TplA>(a));
doThingsWithB(std::forward<TplB>(b));
doThingsWithC(std::forward<TplC>(c));
// do stuff
}
A、B、または C に暗黙的に変換可能な型で大きな関数を呼び出そうとすると、どのように動作するかがわからないため、制限が厳しすぎるかどうかはわかりませんが...
でも... これでうまくいくとしても、本当に他に選択肢がないのでしょうか? (というか…目に優しくない)