Bạn có thể nhận được một cú pháp rất gần với cú pháp ban đầu của bạn với một chút lập trình meta. Bạn muốn xác định bạn CallbackType
và CallbackImpl
:
enum CallbackType
{
SYNC,
ASYNC,
};
template<CallbackType CB, typename... Args>
class CallbackImpl
{
};
Sau đó làm một số điều để có được "đối số mặc định":
// We need to treat the CallbackType argument as a type, not as a value.
// Thus, we need to wrap it in a type.
template <CallbackType cb>
using CallbackT = std::integral_constant<CallbackType, cb>;
// We need to be able to detect if the first type passed in is this CallbackT
template <typename T>
struct is_callback_type
: std::false_type
{};
template <CallbackType cb>
struct is_callback_type<CallbackT<cb>>
: std::true_type
{};
template <typename T>
using is_callback_type_t = typename is_callback_type<T>::type;
// Here we do the work. This is the base case, where the first arg
// is not a CallbackT. Note that this works for an empty Args as well
template <typename AlwaysVoid, typename... Args>
struct construct_callback_impl
{
using type = CallbackImpl<SYNC, Args...>;
};
// If the Args list is of at least size 1,
template <typename CallbackType, typename... Args>
struct construct_callback_impl<
// Use this specialization only if the first type is our CallbackT
typename std::enable_if<is_callback_type_t<CallbackType>::value>::type,
CallbackType,
Args...>
{
// Forward the specified CallbackType on to the CallbackImpl
using type = CallbackImpl<CallbackType::value, Args...>;
};
// Wrap this utility into a nicer calling syntax
template <typename... Args>
using Callback = typename construct_callback_impl<void, Args...>::type;
Sau đó, nó có thể được sử dụng:
Callback<int, int> // type is CallbackImpl<SYNC, int, int>
Callback<CallbackT<SYNC>, int, int> // type is CallbackImpl<SYNC, int, int>
Callback<CallbackT<ASYNC>, int, int> // type is CallbackImpl<ASYNC, int, int>
Callback<> // type is CallbackImpl<SYNC>
Live on Godbolt
Tôi nghĩ rằng nó khá rõ ràng tại sao điều này thường không được thực hiện.
Quá tệ, chúng tôi không thể có những điều tốt đẹp :(, tôi muốn nó luôn luôn gọi CallbackType như một đối số mẫu enum và phần còn lại như variadic, nhưng tôi geuss nó không nói những điều ngoài như vậy. –