我可以使用什么来创建一个函数需要N个参数,其中N在编程时不知道但在编译时是固定的(事实上它是模板参数)?
有问题的功能是一个访问功能,它位于一个性能关键路径中,所以我正在寻找可能的最小开销。
首先想到的是std::initializer_list
虽然便宜,但我已经被告知,它仍然是一个不必要的对象来创建和复制。更重要的是,它有一种时髦的方式来访问initializer_list::begin[i]
(这是我不在乎的另一个对象)的元素,并且不会严格限制N的参数数量,但是是一个小问题。
其次,有模板参数包。这些人是否可行?我必须使用递归来访问N值。
我的目标是试图在这个伪代码中显示:
template<int dim, class T> class linear_searchspace {
template<T...args> operator() (args) {
return std::tie(some_kinda_structure[args[0]], some_kinda_structure[args[1]], some_kinda_structure[args[3]]);
}
};
Hoow我能以递归的方式将它带到真正起作用吗?
澄清: args
应该是坐标。每个坐标是维度中值的索引。所以N坐标通过,将返回N个值。这就像是同时访问N个向量。我想为每个参数添加一个偏移量,它取决于参数的索引,因为它存储了一个数组,其中的偏移量索引对应于参数的索引。计算将是简单的算术。
什么是合适的返回类型?它将访问的结构最有可能保存数值,最多为元组。 std::tuple
是我能做的最好的,还是可以制作更高效的东西?
关于论点,任何事情都会发生,甚至是宏。我很高兴听到你多年来想出的伎俩。
答案 0 :(得分:4)
template <std::size_t DIM, typename T>
class linear_searchspace
{
public:
template <typename... Args>
inline constexpr auto operator()(Args... args) const
noexcept(noexcept(T{std::declval<T>()}))
-> std::tuple<decltype((void)args, T{std::declval<T>()})...>
{
static_assert(sizeof...(Args) == DIM, "wrong number of indices!");
using Tuple = std::tuple<decltype((void)args, T{std::declval<T>()})...>;
return get<Tuple>(make_index_sequence<sizeof...(Args)>{}, args...);
}
private:
template <typename Tuple, typename... Args, std::size_t... Is>
inline constexpr Tuple get(index_sequence<Is...>, Args... args) const
noexcept(noexcept(T{std::declval<T>()}))
{
return Tuple((some_kinda_structure[args] + Is)...);
// ^^^^
// some calculation for each element based on index (here simple addition)
}
T some_kinda_structure[DIM]; // implementation defined
};
(index_sequence
的实现在演示中)
使用上述解决方案,可以使用constexpr
个对象获得最高性能,因为整个操作在编译时进行评估:
int main()
{
constexpr linear_searchspace<5, int> lsp{};
// evaluated at compile-time
constexpr auto t = lsp(0, 1, 2, 3, 4);
static_assert(std::get<1>(t) == 1, "!");
// evaluated at run-time
auto t2 = lsp(4, 3, 2, 1, 0);
assert(std::get<3>(t2) == 3);
}
答案 1 :(得分:2)
double data[]={1,2,3,4,5,6,7,8};
double& toy_map(int x){return data[x];}
template<class...Ts>
auto example(Ts&&...ts)
-> decltype(std::tie(toy_map(std::forward<Ts>(ts))...))
{
static_assert(sizeof...(Ts)==5, "wrong parameter count");
return std::tie(toy_map(std::forward<Ts>(ts))...);
}
请注意,调用toy_map
的顺序是未指定的。
在C ++ 14中,如果您不需要SFINAE,请删除decltype
行。
将5
替换为真实代码中的N
。
如果你想要超载是完美的,你必须通过N
检查SFINAE,但这通常是过度的。
答案 2 :(得分:1)
如果您的函数参数类型相同,则可以通过向量传递它们。将所有数据放入向量中,然后将向量传递给函数。
class Coordinate;
std::vector<Coordinate> my_function(const std::vector<Coordinate>& data)
{
const unsigned int items_in_data = data.size();
//...
return data;
}
矢量是动态的,它可以告诉你里面有多少项。
经验法则是当函数需要许多参数时,将参数放在结构或容器中并传递结构或容器。