7

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 に暗黙的に変換可能な型で大きな関数を呼び出そうとすると、どのように動作するかがわからないため、制限が厳しすぎるかどうかはわかりませんが...

でも... これでうまくいくとしても、本当に他に選択肢がないのでしょうか? (というか…目に優しくない)

4

2 に答える 2

5

static_assertの代わりに s を使用しenable_ifます。IMHO、このオプションは目にやさしいだけでなく、ユーザーフレンドリーでもあります。コンパイラは、引数の型に違反している場合は明確なエラー メッセージを出力しますが、enable_if対応するものでは、一致する関数が見つからないことについて不平を言います。

template<typename TplA, typename TplB, typename TplC>
void doThingsWithABC(TplA&& a, TplB&& b, TplC&& c)
{
  static_assert(std::is_same<A, std::decay<TplA>::type>::value, "arg1 must be of type A");
  static_assert(std::is_same<B, std::decay<TplB>::type>::value, "arg2 must be of type B");
  static_assert(std::is_same<C, std::decay<TplC>::type>::value, "arg3 must be of type C");
    // do stuff
    doThingsWithA(std::forward<TplA>(a));
    doThingsWithB(std::forward<TplB>(b));
    doThingsWithC(std::forward<TplC>(c));
    // do stuff
}
于 2014-06-19T00:26:33.083 に答える