как указать вызываемую концепцию С++, когда выводятся типы вызываемых параметров
Я вызываю шаблонную лямбду из шаблонной функции, выводится тип параметров лямбды. Если тип лямбда-авто, то работает:https://godbolt.org/z/WYxj5G8vx
#include <iostream>
#include <cstdint>
#include <array>
#include <functional>
#include <numeric>
#include <concepts>
template <typename T>
int testf2(T, auto fun) {
std::array<std::uint8_t, sizeof(T)> ar{};
std::iota(ar.begin(), ar.end(), 0);
return fun(ar);
}
int main() {
auto f2 = []<size_t S> (std::array<uint8_t, S> arr) -> int {
return arr[S -1];
};
std::cout << "R = " << testf2(5, f2) << std::endl;
}
я хотел использовать
Используя gcc11.2 или clang13, когда я пытаюсь
template <typename T, size_t S>
int testf2(T, std::invocable<std::array<uint8_t, S>> auto fun) {
std::array<std::uint8_t, sizeof(T)> ar{};
std::iota(ar.begin(), ar.end(), 0);
return fun(ar);
}
Я получаю сообщение об ошибке:
шаблон-кандидат игнорируется: не удалось вывести аргумент шаблона 'S' int testf2(T, std::invocable<std::array<uint8_t, S>> auto fun) {
Я не понимаю, почему компилятор может вывести тип, когда используется только auto, но не с ограничивающей концепцией.
Как правильно использовать понятие в этой ситуации?
Это упрощенная версия кода, на самом деле подпись
============ РЕДАКТИРОВАТЬ 03/03/2022 ==================
Спасибо за правильные ответы, но я упростил код и вопрос, поэтому получаю правильный ответ на неправильный вопрос.
Вам нужно больше контекста, я работаю с микроконтроллерами и хочу создать функцию, которая абстрагирует какую-то транзакцию spi,i2c,modbus и т. д., где один буфер отправляет на подчиненное периферийное устройство и получает буфер в ответ. Функция вычисляет длину буфера записи и чтения, сериализует (при необходимости выполняет преобразование порядка следования байтов), вызывает лямбду для выполнения фактической транзакции в зависимости от транспортного механизма, десериализует и возвращает. Таким образом, длина буферов не может быть рассчитана с помощью (sizeof(Ts) + ...), как это предлагается.
Я сделал более реалистичный пример:живой пример
// return empty array whose size is the sum of the two arrays given as parameters
template<typename T, std::size_t LL, std::size_t RL>
constexpr std::array<T, LL+RL> join(std::array<T, LL>, std::array<T, RL>)
{
return std::array<T, LL+RL>{};
}
// return an array of size sizeof(T) if T is arithmetic, otherwise an empty array
template <typename T>
constexpr auto count_ari(T) {
if constexpr (std::is_arithmetic_v<T>) {
return std::array<uint8_t, sizeof(T)>{};
} else {
return std::array<uint8_t, 0>{};
}
}
// return empty array whose size is the sum of all parameter which are arithmetic
template <typename HEAD, typename... TAIL>
constexpr auto count_ari(HEAD h, TAIL... tail) {
return join(count_ari(h), count_ari(tail...));
}
// create a iota filled array whose size is sum of all arithmetic parameters
// call a lambda given in parameter on this array
// return what has done the lambda
// it's here that I want to constrain parameter "auto fun"
template </*size_t S,*/ typename... ARGS>
int testf2(/*std::invocable<std::array<uint8_t, S>>, */ auto fun, ARGS... args) {
auto ar = count_ari(args...);
std::iota(ar.begin(), ar.end(), 1);
return fun(ar);
}
int main() {
auto f2 = []<size_t S> (std::array<uint8_t, S> arr) -> int {
return arr[S -1];
};
std::cout << "R = " << testf2(f2, 'a') << std::endl;
std::cout << "R = " << testf2(f2, 6, 7l, "foobar") << std::endl;
}
Вопрос остается прежним: есть ли способ добавить ограничение на параметр auto fun функции testf2?
3 ответа
Понятия (и обязательные предложения в целом) не участвуют в выводе аргументов шаблона. Поскольку ваш
S
в данном случае просто
sizeof(T)
, вы должны использовать это.
размер S - сумма всех размеров типов пакета параметров
Тогда сделай это
sizeof(Args) + ...
.
Вы можете использовать
delcltype(count_ari(args...))
чтобы получить результирующий тип массива в качестве параметра шаблона
std::invocable
:
template <typename... ARGS>
int testf2(
std::invocable<decltype(count_ari(std::declval<ARGS>()...))> auto fun,
ARGS... args);
Или же
template <typename... ARGS>
int testf2(auto fun, ARGS... args)
requires std::invocable<decltype(fun), decltype(count_ari(args...))>;
Никол Болас помогает мне найти решение, заключающееся в том, чтобы создать функцию constexpr без аргументов , которая вычисляет размер, и указать точный тип вызываемого объекта с помощью std::function вместо того, чтобы пытаться специализировать auto с концепцией invocable.
template <typename T>
constexpr size_t sizeof_ari() {
if constexpr (std::is_arithmetic_v<T>)
return sizeof(T);
else
return 0;
}
template <typename... ARGS>
constexpr size_t sizeof_aris() {
return (sizeof_ari<ARGS>() + ...);
}
// create a iota filled array whose size is sum of all arithmetic parameters
// call a lambda given in parameter on this array
// return what has done the lambda
template <typename... ARGS>
using lambda_param = std::array<uint8_t, sizeof_aris<ARGS...>()>;
template <typename... ARGS>
int testf2(std::function<int(lambda_param<ARGS...>)> fun, ARGS... args) {
auto ar = make_buf(args...);
std::iota(ar.begin(), ar.end(), 1);
return fun(ar);
}