gpt4 book ai didi

c++ - 在不违反 DRY 原则的情况下对传递的函数对象的参数类型进行模板选择

转载 作者:太空狗 更新时间:2023-10-29 21:12:51 24 4
gpt4 key购买 nike

在这里,我展示了模板函数的两个变体的第一部分 over(vec, f) .

两个版本都遍历一个类似 vector 的对象并为每个元素调用一个函数对象。

一个版本使用两个参数调用函数对象 - 一个元素引用和一个索引 - 第二个版本仅使用元素引用。

想法是让编译器选择与传入的 lambda 相匹配的版本,这样用户就可以在 lambda 签名中表达意图,而不必选择不同名称的自由函数。

代码如下:

#include <vector>
#include <iostream>

template<typename... Ts> struct make_void { typedef void type;};
template<typename... Ts> using void_t = typename make_void<Ts...>::type;


template<class Vector, class F>
auto over(Vector &&vec, F &&f)
-> void_t<decltype(f(vec.operator[](std::declval<std::size_t>()), std::declval<std::size_t>()))>
{
const auto size = vec.size();
for (std::size_t i = 0; i < size; ++i) {
f(vec[i], i);
}
}


template<class Vector, class F>
auto over(Vector &&vec, F &&f)
-> void_t<decltype(f(*vec.begin()))>
{
for (auto &&x : vec) {
f(x);
}
}

int main() {
std::vector<float> vf = {1.0, 1.1, 1.2};

std::cout << "two-argument form:\n";
over(vf, [](auto &&val, auto &&index) {
std::cout << index << " : " << val << std::endl;
});

std::cout << "\none-argument form:\n";
over(vf, [](auto &&val) {
std::cout << val << std::endl;
});
}

问题:

您会看到 void_t<> 中的子句返回类型生成器知道函数的所有实现。我对此感到不满,因为:

a) 它在接口(interface)中泄露了实现细节,并且

b) 它不是干的。

是否有更好的方法来实现这一点:

a) 允许在不改变模板启动器的情况下改变实现,

b) 看起来我的狗不会在我的键盘上打架?

最佳答案

对于这个例子,避免“重复”将比重复本身更复杂,但基本思想是计算函数的 ar-iness,然后适本地调度。这里讨论了一个非常相似的问题:Call function with part of variadic arguments .使用 function_traits 的实现,您可以实现一个名为 dispatch 的函数(我在回答该问题时将其称为 foo):

template<typename F, std::size_t... Is, class Tup>
void dispatch_impl(F && f, std::index_sequence<Is...>, Tup && tup) {
std::forward<F>(f)( std::get<Is>(std::move(tup))... );
}

template<typename F, typename... Args>
void dispatch(F && f, Args&&... args) {
dispatch_impl(std::forward<F>(f),
std::make_index_sequence<function_traits<F>::arity>{},
std::forward_as_tuple(args...) );
}


template<class Vector, class F>
void over(Vector &&vec, F &&f)
{
std::size_t i = 0;
for (auto &&x : vec) {
dispatch(std::forward<F>(f), x, i);
++i;
}
}

这个答案也符合 14。现场示例:http://coliru.stacked-crooked.com/a/14750cef6b735d7e .

编辑:此方法不适用于通用 lambda。所以另一种方法是以这种方式实现调度:

template<typename F, typename T>
auto dispatch(F && f, T && t, std::size_t i) -> decltype((std::forward<F>(f)(std::forward<T>(t)),0)) {
std::forward<F>(f)(std::forward<T>(t));
return 0;
}

template<typename F, typename T>
auto dispatch(F && f, T && t, std::size_t i) -> decltype((std::forward<F>(f)(std::forward<T>(t), i),0)) {
std::forward<F>(f)(std::forward<T>(t),i);
return 0;
}

关于c++ - 在不违反 DRY 原则的情况下对传递的函数对象的参数类型进行模板选择,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46100987/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com