テンプレート化された関数からテンプレート化されたラムダを呼び出すと、ラムダ パラメータの型が推定されます。ラムダのタイプが 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
受け取る callable 以外のものにしたいと考えました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などのトランザクションを抽象化する関数を作成したいと考えています。この関数は、書き込みおよび読み取りバッファーの長さを計算し、シリアル化 (必要に応じてエンディアン変換を行います)、ラムダを呼び出してトランスポート メカニズムに応じて実際のトランザクションを実行し、逆シリアル化して戻ります。したがって、提案されているように、バッファの長さを (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 パラメータに制約を追加する方法はありますか?