2 つの異なる機能を持つテンプレート クラス (OutgoingPacket) があります。
void _prepare() {
assert(false); // this should have been specialized and the native function never called.
}
template <typename Args, typename ... RemArgs>
void _prepare(Args&& args, RemArgs&& ... remArgs) {
assert(false); // this should have been specialized and the native function never called.
}
次に、クラス定義の外で 2 つの特殊化を定義します。
// no args
template <> void OutgoingPacket<PacketServerAck> ::_prepare();
template <> void OutgoingPacket<PacketSup> ::_prepare();
template <> void OutgoingPacket<PacketWelcome> ::_prepare();
template <> void OutgoingPacket<PacketServerPing>::_prepare();
// with args
template <> template <> void OutgoingPacket<PacketGTFO>::_prepare<std::string>(std::string&& message);
template <> template <> void OutgoingPacket<PacketPlayer>::_prepare<std::shared_ptr<User>>(std::shared_ptr<User>&& user);
引数なしで準備するための関数呼び出しは期待どおりに機能しますが、引数付きのオーバーロードへの呼び出しは基本テンプレートを呼び出します。それらはアサートをトリガーします。
なぜこれが起こるのですか?
更新:特殊化の定義を変更して、同じ結果の参照を含めるようにしました:
template <> template <> void OutgoingPacket<PacketGTFO>::_prepare<std::string&&>(std::string&& message);
template <> template <> void OutgoingPacket<PacketPlayer>::_prepare<std::shared_ptr<User>&&>(std::shared_ptr<User>&& user);
余談ですが、私がこのようにしている理由は、基本クラスである OutgoingPacket に、これらのさまざまなバージョンの準備関数が散らばっているとは思わなかったからです。また、異なる OutgoingPackets 間の違いは非常に小さい (~4 行) ため、サブクラス化は適切ではないと感じました。
基本的に、OutgoingPacket オブジェクトは任意の引数を使用して作成され、準備関数に転送されます。
template<typename ... Args>
OutgoingPacket(Args&&... args) {
_prepare(std::forward<Args>(args)...);
}
これが悪い習慣である場合、設計に関するアドバイスをいただけますか?