У меня была такая же проблема. Длина моей колонки была слишком короткой. Что вы можете сделать, это либо увеличить длину, либо сократить текст, который вы хотите поместить в базу данных.
Поскольку, когда пакет параметров функции не является последним параметром, пакет параметров шаблона не может быть выведен из него, и он будет проигнорирован путем вычитания аргумента шаблона.
Таким образом, два аргумента 0, 0
сравниваются с , int
, что дает несоответствие.
Правила дедукции, подобные этой, должны охватывать множество особых случаев (например, что происходит, когда два пакета параметров появляются рядом друг с другом). Поскольку пакеты параметров являются новой функцией в C ++ 11, авторы соответствующего предложения разработали правила консервативно.
Обратите внимание, что пакет параметров шаблона завершающего шаблона будет пустым, если он иначе не выводится. Поэтому, когда вы вызываете конструктор с одним аргументом, все будет работать (обратите внимание на разницу в пакете параметров шаблона и в пакете параметров функции здесь. Первый заголовок, последний - нет).
На самом деле меня немного интересует одно и то же (желая специализироваться на шаблонных пакетах параметров на основе последних аргументов).
Я считаю, что может быть путь вперед, комбинируя разворот набора (std::make_tuple
, back-port std::apply
для C ++ 14 и т. д.):
Вернется сюда, если он будет успешным.
Похожие сообщения:
РЕДАКТОР: Да, выяснилось, не идеально, так как есть дополнительные копии, но это начало.
Если вы знаете более простой способ, чем то, что я перечислю ниже, пожалуйста, не стесняйтесь публиковать сообщения!
Можно делать такие вещи:
auto my_func_callable = [] (auto&& ... args) {
return my_func(std::forward<decltype(args)>(args)...);
};
auto my_func_reversed =
stdcustom::make_callable_reversed(my_func_callable);
И затем реализовать этот код pseduo:
template<typename ... Args>
void my_func(Args&& ... args, const my_special_types& x);
Делая что-то вроде:
template<typename... Args>
void my_func(Args&& ... args)
-> call my_func_reversed(args...)
template<typename... RevArgs>
void my_func_reversed(const my_special_types& x, RevArgs&&... revargs)
-> do separate things with revargs and my_special_types
-> sub_func_reversed(revargs...)
Использование вышеупомянутых утилит.
Есть некоторые (многие) недостатки. Перечислим их ниже.
Это для пользователей C ++ 14 (возможно, C ++ 11), которые хотят заимствовать из будущего (C ++ 17) .
Существует несколько способов сделать это. Я привел некоторые альтернативы в этом примере:
std::apply_impl
(кредит: Orient). Используйте рекурсивные шаблоны для построения обратного index_sequence
(credit: Xeo) reversed_index_sequence
из примера Xeo. Мне это нужно для отладки. >>> name_trait<std::make_index_sequence<5>>::name()
std::index_sequence<0, 1, 2, 3, 4>
>>> name_trait<make_reversed_index_sequence<5>>::name()
std::index_sequence<4, 3, 2, 1, 0>
Я выбрал вариант 1, так как мне легче переваривать. Затем я попытался быстро его формализовать:
namespace stdfuture
) и создание расширения (namespace stdcustom
) Определение фрагментов (адаптация C ++ 17 возможной реализации std::apply
на cppreference.com):
namespace detail {
template <class F, class Tuple, std::size_t... I>
constexpr decltype(auto) apply_reversed_impl(F &&f,
Tuple &&t, std::index_sequence<I...>)
{
// @ref https://stackoverflow.com/a/31044718/7829525
// Credit: Orient
constexpr std::size_t back_index = sizeof...(I) - 1;
return f(std::get<back_index - I>(std::forward<Tuple>(t))...);
}
} // namespace detail
template <class F, class Tuple>
constexpr decltype(auto) apply_reversed(F &&f, Tuple &&t)
{
// Pass sequence by value to permit template inference
// to parse indices as parameter pack
return detail::apply_reversed_impl(
std::forward<F>(f), std::forward<Tuple>(t),
std::make_index_sequence<
std::tuple_size<std::decay_t<Tuple>>::value>{});
}
Использование фрагментов: (из tuple_future_main.output.txt
, скопирован сверху)
auto my_func_callable = [] (auto&& ... args) {
return my_func(std::forward<decltype(args)>(args)...);
};
auto my_func_reversed =
stdcustom::make_callable_reversed(my_func_callable);
Сначала установите шаблоны для окончательных аргументов, которые вы хотите использовать. Вам нужно будет явно перечислить их, поскольку у вас может быть только один пакет параметров.
(Взято из tuple_future_main.cc ):
Пример сценария:
Нам нравится добавлять вещи в контейнеры с именем, что-то вроде формы:
add_item(const Item& item, const string& name, Container& c)
Мы также можем создать элемент с [ужасно большим] числом перегрузок, и мы есть
add_item(${ITEM_CTOR_ARGS}, const string& name, Container& c)
Чтобы сделать это, мы можем объявить следующее:
void add_item_direct(const Item& item, const string& name, Container& c)
Item create_item(Args&&... args)
И затем определить наши общие интерфейсы:
template<typename... Args>
void add_item(Args&&... args) {
...
auto reversed = stdcustom::make_callable_reversed(callable);
reversed(std::forward<Args>(args)...);
}
template<typename ... RevArgs>
void add_item_reversed(Container& c, const string& name, RevArgs&&... revargs)
{
...
static auto ctor = VARIADIC_CALLABLE(create_item,);
...
auto item = ctor_reversed(std::forward<RevArgs>(revargs)...);
add_item_direct(item, name, c);
}
Теперь мы можем делать такие вещи, как: (взято из tuple_future_main.output.txt
)
>>> (add_item(Item("attribute", 12), "bob", c));
>>> (add_item("attribute", 12, "bob", c));
>>> (add_item(Item(2, 2.5, "twelve"), "george", c));
>>> (add_item(2, 2.5, "twelve", "george", c));
>>> (add_item(Item(2, 15.), "again", c));
>>> (add_item(2, 15., "again", c));
>>> c
bob - ctor3: ctor3: ctor1: attribute (12, 10)
bob - ctor3: ctor1: attribute (12, 10)
george - ctor3: ctor3: ctor2: 2, 2.5 (twelve)
george - ctor3: ctor2: 2, 2.5 (twelve)
again - ctor3: ctor3: ctor2: 2, 15 ()
again - ctor3: ctor2: 2, 15 ()
Обратите внимание на дополнительные конструкторы копирования ...: (
make_reversed_index_sequence
и напрямую отправлять функции (упомянутые в других сообщениях SO). Но это больно повторять. Callable
std::enable_if
, которое соответствует как lvalue, так и rvalue-ссылкам, и, возможно, обрабатывать совместимые неявные конструкторы копирования? template<typename ... Args>
void my_func(Args&& ... args) // Greedy
void my_func(magical_ref_match<string>::type, ...)
// If this could somehow automatically snatch `const T&` and `T&&` from the parameter pack...
// And if it can be used flexible with multiple arguments, combinatorically
Из рабочего проекта стандарта N3376 § 14.1 является вероятным разделом, чтобы прочитать об этом.
Ниже приведено § 14.1.11
Если параметр шаблона шаблона класса или шаблона псевдонима имеет шаблон-аргумент по умолчанию, каждый последующий параметр-шаблон должен либо иметь заданный по умолчанию шаблон-аргумент, либо быть пакетом параметров шаблона. Если шаблон-шаблон шаблона первичного класса или шаблон псевдонима является пакетом параметров шаблона, он должен быть последним параметром шаблона. Параметру шаблона шаблона функции не следует за другим параметром шаблона, если только этот параметр шаблона не может быть выведен из списка типов параметров шаблона функции или имеет аргумент по умолчанию.
blockquote>
Итак, должен быть обходной путь. Что-то в этих строках:
namespace v1 {
// Extract the last type in a parameter pack.
// 0, the empty pack has no last type (only called if 1 and 2+ don't match)
template<typename... Ts>
struct last_type {};
// 2+ in pack, recurse:
template<typename T0, typename T1, typename... Ts>
struct last_type<T0, T1, Ts...>:last_type<T1, Ts...>{};
// Length 1, last type is only type:
template<typename T0>
struct last_type<T0> {
typedef T0 type;
};
}
namespace v2 {
template<class T> struct tag_t{using type=T;};
template<class T> using type_t = typename T::type;
template<class...Ts>
using last = type_t< std::tuple_element_t< sizeof...(Ts)-1, std::tuple<tag_t<Ts>...> > >;
template<class...Ts>
struct last_type {
using type=last<Ts...>;
};
}
template<class...Ts>
using last_type=v2::late_type<Ts...>; // or v1
struct S
{
// We accept any number of arguments
// So long as the type of the last argument is an int
// probably needs some std::decay to work right (ie, to implicitly work out that
// the last argument is an int, and not a const int& or whatever)
template <typename... T, typename=typename std::enable_if<std::is_same<int, typename last_type<T...>::type>>::type>
S(T...);
};
, где мы проверяем, что последний тип пакета параметров является int
, или что мы только передали int
.