我从模板函数调用模板 lambda,导出 lambda 参数类型。如果 lambda 的类型为 auto,则它可以工作: 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;
}
我想使用std::invocable
概念来专门化 , 的auto fun
参数testf2
,而不是std::array<std::uint8_t, N>
作为参数的可调用对象。
当我尝试使用 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 时推断类型,但不能使用约束概念。
在这种情况下使用概念的正确方法是什么?
这是代码的简化版本,实际上是的签名testf2
和testf2(auto fun, ARGS... args)
数组的大小是根据参数包类型计算的。
============ 编辑 03/03/2022 ==================
感谢您的正确答案,但我过度简化了代码和问题,所以我得到了错误问题的正确答案。
您需要更多上下文,我使用 MCU,并且想要创建一个函数来抽象某种 spi、i2c、modbus 等事务,其中一个将缓冲区发送到从外设并接收缓冲区作为响应。该函数计算写入和读取缓冲区长度,序列化(如果需要,进行字节序转换),根据传输机制调用 lambda 来执行实际事务,反序列化并返回。因此,缓冲区长度不能按照建议使用 (sizeof(Ts) + ...) 计算。
我做了一个更现实的例子:live example
// 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;
}
问题还是一样:有没有办法在函数 testf2 的 auto fun 参数上添加约束