lambda参数转换为constexpr技巧,然后获取带链接的数组

lambda-parameter to constexpr trick, then get array with linkage

本文关键字:获取 链接 数组 然后 转换 参数 constexpr 技巧 lambda      更新时间:2023-10-16

我发现了一个用例,在这个用例中,向函数提供lambda,并让该函数调用lambda来获得constexpr结果是很方便的(我的真实用例涉及将lambda传递给另一个lambda,其中第一个lambda返回从访问者模式获得的值……但这与我的核心问题无关(。

我正试图得到一个数组";具有联动装置";然后我可以将其用作其他函数的模板参数。我看到了一个非常奇怪的错误;类型的引用的初始化无效"除非我:

  1. 使函数CCD_ 1成为具有丢弃模板参数的模板函数

  1. 为函数arrWithLinkage1提供显式返回类型,例如const array<size_t, 3>&而不是const auto&

我找到了一个变通方法,使用函数arrWithLinkage2,但我担心我可能会进入未定义行为的领域。有人知道吗?

现场示例:https://onlinegdb.com/By9nDmsyw

编辑:感谢Ted(下面的评论(,看起来核心问题是:use of 'auto' in parameter declaration only available with '-fconcepts-ts'因此,这让我对下面使用template<typename Lam>的解决方案感到更舒服,除非有人有其他理由。。。?

// Test that array has linkage
template<auto& arr>
void test() {}
// Get array with linkage
template<size_t... vals>
constexpr auto valsToArr = array<size_t, sizeof...(vals)>{ vals... };
// Lambda to array with linkage
template<size_t... Idx>
constexpr auto& arrWithLinkage(auto lam, index_sequence<Idx...>) {
return valsToArr<lam()[Idx]...>;
}
template<size_t=0> // Only works with this...
constexpr auto& arrWithLinkage1(auto lam) {
constexpr size_t N = lam().size();
return arrWithLinkage(lam, make_index_sequence<N>{});
}
template<typename Lam> // A little less gross-looking, but still concerned that this is UDB
constexpr auto& arrWithLinkage2(Lam lam) {
constexpr size_t N = lam().size();
return arrWithLinkage(lam, make_index_sequence<N>{});
}
int main()
{
auto lam = [](){ return array{1, 2, 3}; };

constexpr const array<size_t, 3>& res = arrWithLinkage1(lam);
test<res>();

return 0;
}

已解决:

(如果Ted的评论是一个答案,他会把它标记为"解决方案",谢谢Ted!(

  1. Ted让我意识到问题确实是我在参数中使用了auto。使用template<typename Lam>确实是一个可以接受的解决方案。从我在谷歌上搜索上述错误并看到其他人做类似的事情来看,我认为解决方案是"定义的行为";。

  2. 我想出了一个更好的整体方法。只需让lambda从一开始就向具有链接的arrWithLinkage10数组返回引用(使用通过模板参数接受一组参数值的模板变量(。

示例:https://onlinegdb.com/Sy-qx3skw

// Test that array has linkage
template<auto& arr>
void test() {
for(auto& val : arr)
cout << val << ", ";
cout << endl;
}
// Get array with linkage
template<size_t... vals>
constexpr auto valsToArr = array<size_t, sizeof...(vals)>{ vals... };
int main()
{
// Just make the lambda return a reference to a constexpr array to begin with
// Avoid the need to convert it to a param pack, then an array template variable
// in order to obtain an array with linkage, that can be passed to test<>()

auto lam = []() -> auto& { return valsToArr<1, 2, 3>; };
constexpr auto& res = lam();
test<res>();

return 0;
}