【发布时间】:2017-03-17 09:56:09
【问题描述】:
我想将boost::range::combine 用作笛卡尔幂,而不是仅用作乘积。
因此,不要像 boost::range::combine(myRange, myRange, myRange); 这样的表达式,而是写像 myCombine(myRange, 3); 这样的东西。
如何实现?
【问题讨论】:
标签: c++11 boost variadic-templates boost-range
我想将boost::range::combine 用作笛卡尔幂,而不是仅用作乘积。
因此,不要像 boost::range::combine(myRange, myRange, myRange); 这样的表达式,而是写像 myCombine(myRange, 3); 这样的东西。
如何实现?
【问题讨论】:
标签: c++11 boost variadic-templates boost-range
在 C++17 或 C++14 中实现它会更容易和更干净,但是因为你用c++11 标记了它,所以这是一个兼容的实现。这是调用 函数对象 f 的通用方法,其中相同的参数重复 N 次。
首先,我们需要一种方法来绑定通用函数对象 f 的第一个参数,然后接受任意数量的参数:
template <typename TF, typename T>
struct bound
{
TF _f;
T _x;
template <typename TFFwd, typename TFwd>
bound(TFFwd&& f, TFwd&& x)
: _f{std::forward<TFFwd>(f)}, _x{std::forward<TFwd>(x)}
{
}
template <typename... Ts>
auto operator()(Ts&&... xs)
-> decltype(_f(_x, std::forward<Ts>(xs)...))
{
return _f(_x, std::forward<Ts>(xs)...);
}
};
template <typename TF, typename T>
auto bind_first(TF&& f, T&& x)
-> decltype(bound<TF&&, T&&>(std::forward<TF>(f), std::forward<T>(x)))
{
return bound<TF&&, T&&>(std::forward<TF>(f), std::forward<T>(x));
}
然后,我们需要一个递归的 helper 来绑定参数 x 多个 TN 次:
template <std::size_t TN>
struct helper
{
template <typename TF, typename T>
auto operator()(TF&& f, T&& x)
-> decltype(helper<TN - 1>{}(bind_first(std::forward<TF>(f), x), x))
{
return helper<TN - 1>{}(bind_first(std::forward<TF>(f), x), x);
}
};
template <>
struct helper<0>
{
template <typename TF, typename T>
auto operator()(TF&& f, T&& x)
-> decltype(f(x))
{
return f(x);
}
};
最后,我们可以提供一个漂亮的界面:
template <std::size_t TN, typename TF, typename T>
auto call_with_same_arg(TF&& f, T&& x)
-> decltype(helper<TN - 1>{}(std::forward<TF>(f), std::forward<T>(x)))
{
return helper<TN - 1>{}(std::forward<TF>(f), std::forward<T>(x));
}
用法:
int add(int a, int b, int c)
{
return a + b + c;
}
int main()
{
assert(call_with_same_arg<3>(add, 5) == 15);
}
这是同一事物的完整 C++17 实现:
template <std::size_t TN, typename TF, typename T>
decltype(auto) call_with_same_arg(TF&& f, T&& x)
{
if constexpr(TN == 1)
{
return f(x);
}
else
{
return call_with_same_arg<TN - 1>(
[&](auto&&... xs){ return f(x, std::forward<decltype(xs)>(xs)...); }, x);
}
}
为了完整起见,C++14 实现:
template <std::size_t TN>
struct helper
{
template <typename TF, typename T>
decltype(auto) operator()(TF&& f, T&& x)
{
return helper<TN - 1>{}(
[&](auto&&... xs){ return f(x, std::forward<decltype(xs)>(xs)...); }, x);
}
};
template <>
struct helper<0>
{
template <typename TF, typename T>
decltype(auto) operator()(TF&& f, T&& x)
{
return f(x);
}
};
template <std::size_t TN, typename TF, typename T>
decltype(auto) call_with_same_arg(TF&& f, T&& x)
{
return helper<TN - 1>{}(std::forward<TF>(f), std::forward<T>(x));
}
【讨论】:
bound 或bind_first。