С вашим решением вы действительно можете отбросить типы, но вы должны сохранить скобки:
Select{ { "up.audit_option" "option" }, {"uep.success"}, {"uep.failure"} }
Также будьте осторожны с инициализированным списком: все элементы внутри будут скопированы.Даже если вы переместитесь:
Select(std::initializer_list<QueryField> fields)
{
for (auto & field : fields)
{
// Actually copy. No move is done.
m_fields.emplace_back(std::move(field));
}
}
Перемещение не допускается, поскольку все элементы в списке инициализатора являются постоянными.
Мое предпочтительное решение - сбросить std::initializer_list
и быть простымв простом и более явном в сложных случаях.
Чтобы разрешить истинные гетерогенные параметры, я воспользуюсь шаблонами с переменными значениями:
template<typename... Args>
Select(Args&&... fields) :
m_fields{QueryField{std::forward<Args>(args)}...} {}
Если вы хотите сохранить конструктор копирования / перемещения,Вы должны отфильтровать некоторые типы параметров:
template<typename T, typename = void typename... Args>
struct is_not_copy_impl : std::false_type {};
template<typename T, typename Arg>
struct is_not_copy_impl<T, std::enable_if_t<std::is_base_of_v<T, std::decay_t<Arg>>>, Arg> : std::true_type {};
template<typename T, typename... Args>
using is_not_copy = is_not_copy_impl<T, void, Args...>;
template<typename... Args, std::enable_if_t<!is_not_copy<Select, Args...>::value>* = nullptr>
Select(Args&&... fields) :
m_fields{QueryField{std::forward<Args>(args)}...} {}
Этот код будет перемещаться при передаче QueryField
и создавать новый при передаче значения другого типа.
использование это:
Select{
QueryField{"up.audit_option" "option"},
"uep.success",
"uep.failure"
};