C++中的多模式瓦拉迪克模板
Multi patterend varadic templates in C++
根据我所读到的内容,我认为这是不可能的,但我希望这里有人可能知道一些解决方案可以让它工作。
我有一个向量(数学(课C++
template <typename T, size_t N> class vec;
并希望创建一个瓦拉迪friend
函数应用于这些向量
即
template <typename F, typename ...Args> friend vec<typename std::result_of<pow(Args&&...)>::type, N> apply(F&& f, const vec<Args, N>&... args);
这是有效的(尚未测试(
但是我想实现这样的模式
template <typename F> friend vec<typename std::result_of<F&&(T&&)>::type, N> apply(F&& f, const vec<T, N>& V);
template <typename F> friend vec<typename std::result_of<F&&(T&&, T&&)>::type, N> apply(F&& f, const vec<T, N>& V1, const vec<T, N>& V2);
template <typename F> friend vec<typename std::result_of<F&&(T&&, T&&)>::type, N> apply(F&& f, const vec<T, N>& V1, const T& V2);
template <typename F> friend vec<typename std::result_of<F&&(T&&, T&&)>::type, N> apply(F&& f, const T& V1, const vec<T, N>& V2);
template <typename F, typename U> friend vec<typename std::result_of<F&&(T&&, U&&)>::type, N> apply(F&& f, const vec<T, N>& V1, const vec<U, N>& V2);
template <typename F, typename U> friend vec<typename std::result_of<F&&(T&&, U&&)>::type, N> apply(F&& f, const vec<T, N>& V1, const U& V2);
template <typename F, typename U> friend vec<typename std::result_of<F&&(U&&, T&&)>::type, N> apply(F&& f, const vec<U, N>& V1, const vec<T, N>& V2);
template <typename F, typename U> friend vec<typename std::result_of<F&&(U&&, T&&)>::type, N> apply(F&& f, const U& V1, const vec<T, N>& V2);
请注意,只需要一个参数是向量,任何标量都会被广播到向量的长度。
这个想法是apply(pow, /*vec<float,N>*/V, /*int*/n) -> {pow(V.v[i],n)...}
i -> 0 ... N
而不是apply(pow, /*vec<float,N>*/V, /*int*/n) -> apply(pow, /*vec<float,N>*/V, /*vec<int,N>*/tmp{/*int*/n}) {pow(V.v[i],tmp.v[i])...}
所以我希望能够写出类似以下内容的东西(C++无效,但它应该给出我想要实现的目标的想法(
template <typename F, typename ...Args> friend vec<typename std::result_of<pow(Args&&...)>::type, N> apply(F&& f, const vec<Args, N>&||scalar<Args>::type... args) {
vec<typename std::result_of<pow(Args&&...)>::type, N> r;
for (int i= 0; i < N; i++) { r = f((is_vec<Args>?args.v[i]:args)...); }
return r;
}
编辑:
根据弗兰克的评论,我正在寻找类似的东西
template<typename F, typename ...Args, size_t N>
vec<typename std::enable_if<sum<is_vec<Args,N>...>::value > 0, std::result_of<F&&(base_type<Args>::type&&...)>::type>::type, N>
(F&& f, Args&&...args) {
vec<typename std::result_of<F&&(base_type<Args>::type&&...)>::type, N> result;
for(std::size_t i = 0 ; i < N ; ++i) { result.v[i] = f(extract_v(std::forward<Args>(args),i)...); }
return result;
}
但是我不确定这个版本是否可以编译,因为它可能太模棱两可而无法损害N
的价值。
不确定你到底想要什么,但是...
在我看来,自定义类型特征可以从类型列表中提取Vec
的维度很有用,iff(当且仅当(在类型列表中至少有一个Vec
并且没有不同长度的Vec
。
我建议如下,主要基于模板专业化,
template <std::size_t, typename ...>
struct dimVec;
// ground case for no Vecs: unimplemented for SFINAE failure !
template <>
struct dimVec<0U>;
// ground case with one or more Vecs: size fixed
template <std::size_t N>
struct dimVec<N> : public std::integral_constant<std::size_t, N>
{ };
// first Vec: size detected
template <std::size_t N, typename T, typename ... Ts>
struct dimVec<0U, Vec<T, N>, Ts...> : public dimVec<N, Ts...>
{ };
// another Vec of same size: continue
template <std::size_t N, typename T, typename ... Ts>
struct dimVec<N, Vec<T, N>, Ts...> : public dimVec<N, Ts...>
{ };
// another Vec of different size: unimplemented for SFINAE failure !
template <std::size_t N1, std::size_t N2, typename T, typename ... Ts>
struct dimVec<N1, Vec<T, N2>, Ts...>;
// a not-Vec type: continue
template <std::size_t N, typename T, typename ... Ts>
struct dimVec<N, T, Ts...> : public dimVec<N, Ts...>
{ };
借助模板静态变量
template <typename ... Args>
static constexpr auto dimVecV { dimVec<0U, Args...>::value };
现在应该很容易。
您可以编写一个apply()
函数,该函数接收Args...
类型的参数的可变参数列表,并且是否启用了 SFINAEdimVecV<Args...>
template <typename F, typename ... Args, std::size_t N = dimVecV<Args...>>
auto apply (F && f, Args ... as)
{ return applyH1(std::make_index_sequence<N>{}, f, as...); }
请注意,N
变量用于 SFINAE 启用/禁用函数,但它本身很有用:它用于将std::index_sequence
从0
传递到N-1
到第一个帮助程序函数applyH1()
template <std::size_t ... Is, typename F, typename ... Args>
auto applyH1 (std::index_sequence<Is...> const &, F && f, Args ... as)
-> Vec<decltype(applyH2<0U>(f, as...)), sizeof...(Is)>
{ return { applyH2<Is>(f, as...)... }; }
使用从第二个帮助程序函数计算的单个值初始化返回的Vec
applyH2()
template <std::size_t I, typename F, typename ... Args>
auto applyH2 (F && f, Args ... as)
{ return f(extrV<I>(as)...); }
使用一组模板函数extrV()
template <std::size_t I, typename T, std::size_t N>
constexpr auto extrV (Vec<T, N> const & v)
{ return v[I]; }
template <std::size_t I, typename T>
constexpr auto extrV (T const & v)
{ return v; }
从Vec
中提取第I
个元素或传递标量值。
它有点长,但不是特别复杂。
以下是完整的工作示例
#include <array>
#include <iostream>
#include <type_traits>
template <typename T, std::size_t N>
class Vec;
template <std::size_t, typename ...>
struct dimVec;
// ground case for no Vecs: unimplemented for SFINAE failure !
template <>
struct dimVec<0U>;
// ground case with one or more Vecs: size fixed
template <std::size_t N>
struct dimVec<N> : public std::integral_constant<std::size_t, N>
{ };
// first Vec: size detected
template <std::size_t N, typename T, typename ... Ts>
struct dimVec<0U, Vec<T, N>, Ts...> : public dimVec<N, Ts...>
{ };
// another Vec of same size: continue
template <std::size_t N, typename T, typename ... Ts>
struct dimVec<N, Vec<T, N>, Ts...> : public dimVec<N, Ts...>
{ };
// another Vec of different size: unimplemented for SFINAE failure !
template <std::size_t N1, std::size_t N2, typename T, typename ... Ts>
struct dimVec<N1, Vec<T, N2>, Ts...>;
// a not-Vec type: continue
template <std::size_t N, typename T, typename ... Ts>
struct dimVec<N, T, Ts...> : public dimVec<N, Ts...>
{ };
template <typename ... Args>
static constexpr auto dimVecV { dimVec<0U, Args...>::value };
template <std::size_t I, typename T, std::size_t N>
constexpr auto extrV (Vec<T, N> const & v)
{ return v[I]; }
template <std::size_t I, typename T>
constexpr auto extrV (T const & v)
{ return v; }
template <typename T, std::size_t N>
class Vec
{
private:
std::array<T, N> d;
public:
template <typename ... Ts>
Vec (Ts ... ts) : d{{ ts... }}
{ }
T & operator[] (int i)
{ return d[i]; }
T const & operator[] (int i) const
{ return d[i]; }
};
template <std::size_t I, typename F, typename ... Args>
auto applyH2 (F && f, Args ... as)
{ return f(extrV<I>(as)...); }
template <std::size_t ... Is, typename F, typename ... Args>
auto applyH1 (std::index_sequence<Is...> const &, F && f, Args ... as)
-> Vec<decltype(applyH2<0U>(f, as...)), sizeof...(Is)>
{ return { applyH2<Is>(f, as...)... }; }
template <typename F, typename ... Args, std::size_t N = dimVecV<Args...>>
auto apply (F && f, Args ... as)
{ return applyH1(std::make_index_sequence<N>{}, f, as...); }
long foo (int a, int b)
{ return a + b + 42; }
int main ()
{
Vec<int, 3U> v3;
Vec<int, 2U> v2;
auto r1 { apply(foo, v2, v2) };
auto r2 { apply(foo, v3, v3) };
auto r3 { apply(foo, v3, 0) };
static_assert( std::is_same<decltype(r1), Vec<long, 2U>>{}, "!" );
static_assert( std::is_same<decltype(r2), Vec<long, 3U>>{}, "!" );
static_assert( std::is_same<decltype(r3), Vec<long, 3U>>{}, "!" );
// apply(foo, v2, v3); // compilation error
// apply(foo, 1, 2); // compilation error
}
您可以通过部分模板专用化和参数包扩展的组合来实现所需的目标。
#include <array>
template<typename T, std::size_t N>
using Vec = std::array<T, N>;
template<typename T>
struct extract {
static auto exec(T const& v, std::size_t) {return v;}
enum { size = 1 };
};
template<typename T, std::size_t N>
struct extract<Vec<T,N>> {
static auto exec(Vec<T,N> const& v, std::size_t i) {return v[i];}
enum {size = N};
};
template<typename T>
auto extract_v(T const& v, std::size_t i) {return extract<T>::exec(v, i);}
template<typename... args>
struct extract_size {
enum {size = 1};
};
template<typename first, typename... rest>
struct extract_size<first, rest...> {
enum {
rest_size_ = extract_size<rest...>::size,
self_size_ = extract<first>::size,
size = rest_size_ > self_size_ ? rest_size_ : self_size_
};
static_assert(self_size_ == 1 || rest_size_ == 1 || rest_size_ == self_size_, "");
};
template<typename F, typename... args_t>
auto apply(F const& cb, args_t&&... args) {
constexpr std::size_t size = extract_size<std::decay_t<args_t>...>::size;
using result_t = decltype(cb(extract_v(std::forward<args_t>(args),0)...));
Vec<result_t, size> result;
for(std::size_t i = 0 ; i < size ; ++i) {
result[i] = cb(extract_v(std::forward<args_t>(args),i)...);
}
return result;
}
- 具有奇怪重复模板模式的派生类中的成员变量已损坏
- 芬威克树(BIT).找到具有给定累积频率的最小索引,单位为 O(logN)
- 为什么在保护模式下继承升级不起作用
- 如何在全屏模式下(在OpenGL中)使背景透明
- 为什么使用__LINE_的代码在发布模式下在MSVC下编译,而不是在调试模式下
- 派生类是否可以在抽象工厂设计模式中具有数据成员
- 此模式的C++RegEx
- avrogencpp能为模式中的每种类型生成单独的头文件吗
- 使用可变模板的Broadcaster/Listener模式
- c++方法参数只能在linux的发布模式下自行更改
- 资源管理设计模式
- 使用 mod_gsoap 部署服务时,如何在 Gsoap 中更改 soap 上下文的模式?
- C++ 无法在字符数组中使用 for 循环打印字母模式
- 小字符串优化(调试与发布模式)
- 可视化C++:发布模式的运行时库作为'Multi-threaded Debug DLL'
- 如何设计具有不同类型的通知和观察器的观察者模式?
- 在C++的一系列数字中查找重复模式
- C++中的多模式瓦拉迪克模板
- USACO 牛障碍赛:迪尼克的算法/对指针未注册的更改
- 平方根的科迪克