C++ 扩展C+中的多模式变量模板+;
这个问题是我收到解决方案的前一个问题的后续问题:C++ 扩展C+中的多模式变量模板+;,c++,templates,c++14,variadic-templates,template-meta-programming,C++,Templates,C++14,Variadic Templates,Template Meta Programming,这个问题是我收到解决方案的前一个问题的后续问题: #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: unim
#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
}
编辑:
我只是想出了一个可能的解决方案,或者至少是其中的一部分,见下文
template <size_t ...N>
struct tensor_helper {
template <size_t I, typename T, size_t ...M> static tensorGet(const tensor<T, M...>& V) { return V.v[I % product<M...>::value]; }
template <size_t I, typename T> static tensorGet(const T& V) { return V; }
template <std::size_t I, typename F, typename ...Args>
static auto applyH2 (F && f, Args ...as) -> decltype(f(std::declval<typename base_type<Args>::type>()...))
{ return f(tensorGet<I>(as)...); }
template <size_t ... Is, typename F, typename ... Args>
static auto applyH1(std::index_sequence<Is...> const &..., F && f, Args ... as) -> tensor<decltype(f(std::declval<typename base_type<Args>::type>()...)), N...>
{ return make_tensor<decltype(f(std::declval<typename base_type<Args>::type>()...)), N...>({applyH2<Is>(f, as...)... }); }
}
template <typename F, typename ...Args, size_t ...N = tensorSize<Args...> /* How do I get a list here? */>
auto apply (F && f, Args ... as)
{ return tensor_helper<N...>::applyH1(std::make_index_sequence<product<N...>>{}..., f, as...); }
模板
结构张量{
模板静态tensorGet(常量tensor&V){返回V.V[I%product::value];}
模板静态张量集(常数T&V){return V;}
模板
静态autoapplyh2(F&&F,Args…as)->decltype(F(std::declval在概念上非常相似,但在两个维度上,它变成了一场噩梦
我建议使用二维(N
和M
)的dimMat
,而不是DIMMEC
),并针对不可接受的情况(不同尺寸的VEC或mat,尺寸与mat不兼容的vect)进行SFINAE故障处理;我不确定是否所有情况都得到了管理,但应如下所示:
template <std::size_t, std::size_t, typename ...>
struct dimMat;
// ground case for no Vecs and no Mats: unimplemented for SFINAE failure
template <>
struct dimMat<0U, 0U>;
// ground case with one or more Vecs and/or Mats: sizes fixed
template <std::size_t N, std::size_t M>
struct dimMat<N, M>
{
static constexpr std::size_t valN { N };
static constexpr std::size_t valM { M };
};
// first Vec: M detected
template <std::size_t M, typename T, typename ... Ts>
struct dimMat<0U, 0U, Vec<T, M>, Ts...> : public dimMat<0U, M, Ts...>
{ };
// first Mat: N and M detected
template <std::size_t N, std::size_t M, typename T, typename ... Ts>
struct dimMat<0U, 0U, Mat<T, N, M>, Ts...> : public dimMat<N, M, Ts...>
{ };
// first Mat after a correct Vect: N detected
template <std::size_t N, std::size_t M, typename T, typename ... Ts>
struct dimMat<0U, M, Mat<T, N, M>, Ts...> : public dimMat<N, M, Ts...>
{ };
// another Vec of correct size: continue
template <std::size_t N, std::size_t M, typename T, typename ... Ts>
struct dimMat<N, M, Vec<T, M>, Ts...> : public dimMat<N, M, Ts...>
{ };
// another Mat of correct sizes: continue
template <std::size_t N, std::size_t M, typename T, typename ... Ts>
struct dimMat<N, M, Mat<T, N, M>, Ts...> : public dimMat<N, M, Ts...>
{ };
// another Vec of different size: unimplemented for SFINAE failure
template <std::size_t N, std::size_t M1, std::size_t M2, typename T,
typename ... Ts>
struct dimMat<N, M1, Vec<T, M2>, Ts...>;
// another Mat of different sizes: unimplemented for SFINAE failure
template <std::size_t N1, std::size_t N2, std::size_t M1, std::size_t M2,
typename T, typename ... Ts>
struct dimMat<N1, M1, Mat<T, N2, M2>, Ts...>;
// a not-Vec, not-Mat type: continue
template <std::size_t N, std::size_t M, typename T, typename ... Ts>
struct dimMat<N, M, T, Ts...> : public dimMat<N, M, Ts...>
{ };
对于applyMH1()
两种情况:如果N
为零,那么第一个参数是一个空索引列表,那么我们有vec情况
// Vec case: the first index list is empty: call applyH2()
template <std::size_t ... Js, typename F, typename ... Args>
auto applyMH1 (std::index_sequence<> const &,
std::index_sequence<Js...> const &, F && f, Args ... as)
-> Vec<decltype(applyH2<0U>(f, as...)), sizeof...(Js)>
{ return { applyH2<Js>(f, as...)... }; }
和applyMH3()
下面是一个完整的编译示例
#include <array>
#include <iostream>
#include <type_traits>
template <typename T, std::size_t N>
class Vec;
template <typename T, std::size_t N, std::size_t M>
struct Mat;
template <std::size_t, std::size_t, typename ...>
struct dimMat;
// ground case for no Vecs and no Mats: unimplemented for SFINAE failure
template <>
struct dimMat<0U, 0U>;
// ground case with one or more Vecs and/or Mats: sizes fixed
template <std::size_t N, std::size_t M>
struct dimMat<N, M>
{
static constexpr std::size_t valN { N };
static constexpr std::size_t valM { M };
};
// first Vec: M detected
template <std::size_t M, typename T, typename ... Ts>
struct dimMat<0U, 0U, Vec<T, M>, Ts...> : public dimMat<0U, M, Ts...>
{ };
// first Mat: N and M detected
template <std::size_t N, std::size_t M, typename T, typename ... Ts>
struct dimMat<0U, 0U, Mat<T, N, M>, Ts...> : public dimMat<N, M, Ts...>
{ };
// first Mat after a correct Vect: N detected
template <std::size_t N, std::size_t M, typename T, typename ... Ts>
struct dimMat<0U, M, Mat<T, N, M>, Ts...> : public dimMat<N, M, Ts...>
{ };
// another Vec of correct size: continue
template <std::size_t N, std::size_t M, typename T, typename ... Ts>
struct dimMat<N, M, Vec<T, M>, Ts...> : public dimMat<N, M, Ts...>
{ };
// another Mat of correct sizes: continue
template <std::size_t N, std::size_t M, typename T, typename ... Ts>
struct dimMat<N, M, Mat<T, N, M>, Ts...> : public dimMat<N, M, Ts...>
{ };
// another Vec of different size: unimplemented for SFINAE failure
template <std::size_t N, std::size_t M1, std::size_t M2, typename T,
typename ... Ts>
struct dimMat<N, M1, Vec<T, M2>, Ts...>;
// another Mat of different sizes: unimplemented for SFINAE failure
template <std::size_t N1, std::size_t N2, std::size_t M1, std::size_t M2,
typename T, typename ... Ts>
struct dimMat<N1, M1, Mat<T, N2, M2>, Ts...>;
// a not-Vec, not-Mat type: continue
template <std::size_t N, std::size_t M, typename T, typename ... Ts>
struct dimMat<N, M, T, Ts...> : public dimMat<N, M, Ts...>
{ };
template <typename ... Args>
static constexpr auto dimMatN { dimMat<0U, 0U, Args...>::valN };
template <typename ... Args>
static constexpr auto dimMatM { dimMat<0U, 0U, Args...>::valM };
template <std::size_t, typename ...>
struct dimVec;
// ground case for no Vecs: unimplemented !
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 !
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 <std::size_t I, typename T, std::size_t N, std::size_t M>
constexpr auto extrV (Mat<T, N, M> const & v)
{ return 0; }
template <std::size_t I, std::size_t J, typename T,
std::size_t N, std::size_t M>
constexpr auto extrM (Mat<T, N, M> const & v)
{ return v[I][J]; }
template <std::size_t I, std::size_t J, typename T>
constexpr auto extrM (T const & v)
{ return extrV<J>(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 <typename T, std::size_t N, std::size_t M>
struct Mat
{
std::array<std::array<T, M>, N> m;
auto & operator[] (int i)
{ return m[i]; }
auto const & operator[] (int i) const
{ return m[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...); }
template <std::size_t I, std::size_t J, typename F, typename ... Args>
auto applyMH3 (F && f, Args ... as)
{ return f(extrM<I, J>(as)...); }
template <std::size_t I, std::size_t ... Js, typename F, typename ... Args>
auto applyMH2 (std::index_sequence<Js...> const &, F && f, Args ... as)
-> std::array<decltype(applyMH3<0U, 0U>(f, as...)), sizeof...(Js)>
{ return {{ applyMH3<I, Js>(f, as...)... }}; }
// Vec case: the first index list is empty: call applyH2()
template <std::size_t ... Js, typename F, typename ... Args>
auto applyMH1 (std::index_sequence<> const &,
std::index_sequence<Js...> const &, F && f, Args ... as)
-> Vec<decltype(applyH2<0U>(f, as...)), sizeof...(Js)>
{ return { applyH2<Js>(f, as...)... }; }
template <std::size_t ... Is, std::size_t ... Js, typename F,
typename ... Args>
auto applyMH1 (std::index_sequence<Is...> const &,
std::index_sequence<Js...> const & js, F && f, Args ... as)
-> Mat<decltype(applyMH3<0U, 0U>(f, as...)), sizeof...(Is), sizeof...(Js)>
{ return {{{ applyMH2<Is>(js, f, as...) ... }}}; }
template <typename F, typename ... Args, std::size_t N = dimMatN<Args...>,
std::size_t M = dimMatM<Args...>>
auto applyM (F && f, Args ... as)
{ return applyMH1(std::make_index_sequence<N>{},
std::make_index_sequence<M>{},
f, as...); }
long foo (int a, int b)
{ return a + b + 42; }
int main ()
{
Vec<int, 3U> v3;
Vec<int, 2U> v2;
Mat<int, 2U, 3U> m23;
Mat<int, 2U, 4U> m24;
auto r1 { applyM(foo, v2, v2) };
auto r2 { applyM(foo, v3, v3) };
auto r3 { applyM(foo, v3, 0) };
auto r4 { applyM(foo, v3, m23) };
auto r5 { applyM(foo, m24, 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>>{}, "!" );
static_assert( std::is_same<decltype(r4), Mat<long, 2U, 3U>>{}, "!" );
static_assert( std::is_same<decltype(r5), Mat<long, 2U, 4U>>{}, "!" );
//applyM(foo, v2, v3); // compilation error
//applyM(foo, 1, 2); // compilation error
//applyM(foo, v2, m23); // compilation error
//applyM(foo, m24, m23); // compilation error
}
#include <array>
#include <string>
#include <iostream>
template <typename T, std::size_t ...>
struct tensor;
template <typename T, std::size_t N, std::size_t ... Ns>
struct tensor<T, N, Ns...>
{
using nextT = std::conditional_t<(sizeof...(Ns) > 0U),
tensor<T, Ns...>, T>;
std::array<nextT, N> value;
auto const & operator[] (std::size_t i) const
{ return value[i]; }
auto & operator[] (std::size_t i)
{ return value[i]; }
};
// scalar case: return value
template <std::size_t ... Is, typename T>
constexpr auto extrV (std::index_sequence<Is...> const &, T const & t)
{ return t; }
// tensor case with lower dimension: skip the first requested index
template <std::size_t I0, std::size_t ... Is,
typename T, std::size_t ... Js>
constexpr auto extrV
(std::index_sequence<I0, Is...> const &, tensor<T, Js...> const & t,
std::enable_if_t<(sizeof...(Is) >= sizeof...(Js))> * = nullptr)
{ return extrV(std::index_sequence<Is...>{}, t); }
// tensor case with exact dimension: use the first requested index
template <std::size_t I0, std::size_t ... Is,
typename T, std::size_t ... Js>
constexpr auto extrV
(std::index_sequence<I0, Is...> const &, tensor<T, Js...> const & t,
std::enable_if_t<(sizeof...(Is)+1U == sizeof...(Js))> * = nullptr)
{ return extrV(std::index_sequence<Is...>{}, t[I0]); }
template <typename, typename, typename, typename = std::true_type>
struct gsHelper;
// sequences of different lengths: skipp the first index in longest
template <typename T, std::size_t I0, std::size_t ... Is, std::size_t ... Js>
struct gsHelper<T, std::index_sequence<I0, Is...>,
std::index_sequence<Js...>,
std::integral_constant<bool, (sizeof...(Is) >= sizeof...(Js))>>
: public gsHelper<T, std::index_sequence<Is...>,
std::index_sequence<Js...>>
{ };
template <typename T, typename IS>
struct gsHelper<T, IS, IS>
{ using type = T; };
template <typename, typename, bool>
struct greaterSeq;
template <typename T1, typename T2>
struct greaterSeq<T1, T2, true> : public gsHelper<T1, T1, T2>
{ };
template <typename T1, typename T2>
struct greaterSeq<T1, T2, false> : public gsHelper<T2, T2, T1>
{ };
template <typename T1, typename T2, bool B>
using greaterSeqT = typename greaterSeq<T1, T2, B>::type;
template <typename ...>
struct commonDims;
// ground case: define type as surviving parameter
template <std::size_t I0, std::size_t ... Is>
struct commonDims<std::index_sequence<I0, Is...>>
{ using type = std::index_sequence<I0, Is...>; };
// no tensor type: continue
template <typename IS, typename T0, typename ... Ts>
struct commonDims<IS, T0, Ts...> : public commonDims<IS, Ts...>
{ };
// tensor type: continue with bigger common index list (if any)
template <std::size_t ... Is, typename T, std::size_t ... Js,
typename ... Ts>
struct commonDims<std::index_sequence<Is...>, tensor<T, Js...>, Ts...>
: public commonDims<greaterSeqT<std::index_sequence<Is...>,
std::index_sequence<Js...>,
(sizeof...(Is) > sizeof...(Js))>, Ts...>
{ };
template <typename ... Ts>
using commonDimsT = typename commonDims<std::index_sequence<>, Ts...>::type;
template <typename IS, typename F, typename ... Args>
auto call (IS const & is, F && f, Args const & ... as)
{ return f(extrV(is, as)...); }
template <std::size_t ... Is, std::size_t ... Js, std::size_t ... Ks,
typename F, typename ... Args>
auto applyH2 (std::index_sequence<Is...> const &,
std::index_sequence<Js...> const &,
std::index_sequence<Ks...> const & ks,
F && f, Args const & ... as)
-> tensor<
decltype(call(std::index_sequence<(Is, 0U)..., 0U, (Ks, 0U)...>{},
f, as...)), sizeof...(Js), Ks...>
{ return {{{ applyH1(std::index_sequence<Is..., Js>{},
ks, f, as...) ... }}}; }
template <typename IS, typename F, typename ... Args>
auto applyH1 (IS const & is, std::index_sequence<> const &,
F && f, Args const & ... as)
{ return call(is, f, as...); }
template <typename IS, std::size_t J0, std::size_t ... Js,
typename F, typename ... Args>
auto applyH1 (IS const & is, std::index_sequence<J0, Js...> const &,
F && f, Args const & ... as)
{ return applyH2(is, std::make_index_sequence<J0>{},
std::index_sequence<Js...>{}, f, as...); }
template <typename F, typename ... Args, typename IS = commonDimsT<Args...>>
auto apply (F && f, Args const & ... as)
{ return applyH1(std::index_sequence<>{}, IS{}, f, as...); }
long foo (int a, int b)
{ return a + b + 42; }
int main ()
{
tensor<int, 2, 3, 4, 5> t0;
t0[0][0][0][0] = 1;
using t1 = commonDimsT<tensor<int, 1>, long, tensor<long, 3, 2, 1>, int>;
static_assert(std::is_same<t1, std::index_sequence<3, 2, 1>>{}, "!");
auto r1 { apply(foo, tensor<int, 3, 2, 1>{}, 0) };
auto r2 { apply(foo, tensor<int, 3, 2, 1>{}, tensor<int, 3, 2, 1>{}) };
auto r3 { apply(foo, tensor<int, 3, 2, 1>{}, tensor<int, 2, 1>{}) };
auto r4 { apply(foo, tensor<int, 3, 2, 1>{}, tensor<int, 1>{}) };
auto r5 { apply(foo, 0, tensor<int, 1>{}) };
static_assert(std::is_same<decltype(r1), tensor<long, 3, 2, 1>>{}, "!");
static_assert(std::is_same<decltype(r2), tensor<long, 3, 2, 1>>{}, "!");
static_assert(std::is_same<decltype(r3), tensor<long, 3, 2, 1>>{}, "!");
static_assert(std::is_same<decltype(r4), tensor<long, 3, 2, 1>>{}, "!");
static_assert(std::is_same<decltype(r5), tensor<long, 1>>{}, "!");
// compilation errors (no common tensor)
//apply(foo, 0, 0);
//apply(foo, tensor<int, 3, 2, 1>{}, tensor<int, 2>{});
}
#包括
#包括
#包括
模板
Vec类;
模板
结构垫;
模板
结构dimMat;
//无VEC和无垫接地情况:SFINAE故障未实施
模板
结构dimMat;
//带有一个或多个VEC和/或垫的接地外壳:尺寸固定
模板
结构dimMat
{
静态constexpr std::size_t valN{N};
静态constexpr std::size_t valM{M};
};
//检测到第一个Vec:M
模板
结构dimMat:公共dimMat
{ };
//第一层:检测到N和M
模板
结构dimMat:公共dimMat
{ };
//检测到正确矢量后的第一个Mat:N
模板
结构dimMat:公共dimMat
{ };
//另一个大小正确的Vec:继续
模板
结构dimMat:公共dimMat
{ };
//另一张正确尺寸的垫子:继续
模板
结构dimMat:公共dimMat
{ };
//另一个不同大小的Vec:未实现SFINAE故障
模板
结构dimMat;
//另一种不同尺寸的垫子:未实现SFINAE故障
模板
结构dimMat;
//非Vec、非Mat类型:继续
模板
结构dimMat:公共dimMat
{ };
模板
静态constexpr auto dimMatN{dimMat::valN};
模板
静态constexpr自动调光atm{dimMat::valM};
模板
结构dimVec;
//无VEC的基本情况:未实现!
模板
结构dimVec;
//带有一个或多个VEC的接地外壳:尺寸固定
模板
struct dimVec:public std::integral_常量
{ };
//第一个向量:检测到大小
模板
结构dimVec:公共dimVec
{ };
//另一个相同大小的Vec:继续
模板
结构dimVec:公共dimVec
{ };
//另一个不同大小的Vec:未实现!
模板
结构dimVec;
//非Vec类型:是否继续
模板
结构dimVec:公共dimVec
{ };
模板
静态constexpr auto dimVecV{dimVec::value};
模板
constexpr自动输出(Vec const&v)
{返回v[I];}
模板
constexpr自动输出(T const&v)
{返回v;}
模板
constexpr自动拉伸(材料const&v)
{返回0;}
模板
constexpr自动拉伸(材料常数和v)
{返回v[I][J];}
模板
constexpr自动输出(T const&v)
{return extrV(v);}
模板
Vec类
{
私人:
std::数组d;
公众:
模板
向量(Ts…Ts):d{Ts..}
{ }
T&operator[](国际一级)
{返回d[i];}
T常量和运算符[](int i)常量
{返回d[i];}
};
模板
结构垫
{
std::数组m;
自动和操作员[](int i)
{返回m[i];}
自动常量和运算符[](int i)常量
{返回m[i];}
};
模板
自动应用程序2(F&&F,参数…as)
{返回f(extrV(as)…);}
模板
自动应用程序1(std::index_序列常量&,F&&F,Args…as)
->Vec
{返回{applyH2(f,as…)};}
模板
自动应用(F&&F,参数…作为)
{返回applyH1(std::make_index_sequence{},f,as…;}
模板
自动应用程序mH3(F&&F,参数…as)
{返回f(extrM(as)…);}
模板
auto-applyMH2(std::index_sequence const&,F&&F,Args…as)
->std::数组
{return{{applyMH3(f,as…)};}
//Vec案例:第一个索引列表为空:call applyH2()
模板
自动应用程序Mh1(标准::索引\u序列常量&,
std::index_序列常数&,F&&F,参数…as)
->Vec
{返回{applyH2(f,as…)};}
模板
自动应用程序Mh1(标准::索引\u序列常量&,
std::index_序列const&js、F&F、Args…as)
->垫子
{返回{{applyMH2(js,f,as…}}};}
模板
自动应用程序(F&&F,参数…as)
{返回applyMH1(std::make_index_sequence{},
std::make_index_sequence{},
f、 as…;}
长富(内部a、内部b)
{返回a+b+42;}
int main()
{
Vec-v3;
Vec v2;
Mat m23;
Mat m24;
自动r1{applyM(foo,v2,v2)};
自动r2{applyM(foo,v3,v3)};
自动r3{applyM(foo,v3,0)};
自动r4{applyM(foo,v3,m23)};
自动r5{applyM(foo,m24,0)};
静态断言(std::is_same{},“!”);
静态断言(std::is_same{},“!”);
静态断言(std::is_same{},“!”);
静态断言(std::is_same{},“!”);
静态断言(std::is_same{},“!”);
//applyM(foo,v2,v3);//编译错误
//applyM(foo,1,2);//编译错误
//applyM(foo,v2,m23);//编译错误
//applyM(foo,m24,m23);//编译错误
}
在概念上非常相似,但在两个维度上,这将成为一场噩梦
我建议使用二维(N
和M
)的dimMat
,而不是DIMMEC
),并针对不可接受的情况(不同尺寸的VEC或mat,尺寸与mat不兼容的vect)进行SFINAE故障处理;我不确定是否所有情况都得到了管理,但应如下所示:
template <std::size_t, std::size_t, typename ...>
struct dimMat;
// ground case for no Vecs and no Mats: unimplemented for SFINAE failure
template <>
struct dimMat<0U, 0U>;
// ground case with one or more Vecs and/or Mats: sizes fixed
template <std::size_t N, std::size_t M>
struct dimMat<N, M>
{
static constexpr std::size_t valN { N };
static constexpr std::size_t valM { M };
};
// first Vec: M detected
template <std::size_t M, typename T, typename ... Ts>
struct dimMat<0U, 0U, Vec<T, M>, Ts...> : public dimMat<0U, M, Ts...>
{ };
// first Mat: N and M detected
template <std::size_t N, std::size_t M, typename T, typename ... Ts>
struct dimMat<0U, 0U, Mat<T, N, M>, Ts...> : public dimMat<N, M, Ts...>
{ };
// first Mat after a correct Vect: N detected
template <std::size_t N, std::size_t M, typename T, typename ... Ts>
struct dimMat<0U, M, Mat<T, N, M>, Ts...> : public dimMat<N, M, Ts...>
{ };
// another Vec of correct size: continue
template <std::size_t N, std::size_t M, typename T, typename ... Ts>
struct dimMat<N, M, Vec<T, M>, Ts...> : public dimMat<N, M, Ts...>
{ };
// another Mat of correct sizes: continue
template <std::size_t N, std::size_t M, typename T, typename ... Ts>
struct dimMat<N, M, Mat<T, N, M>, Ts...> : public dimMat<N, M, Ts...>
{ };
// another Vec of different size: unimplemented for SFINAE failure
template <std::size_t N, std::size_t M1, std::size_t M2, typename T,
typename ... Ts>
struct dimMat<N, M1, Vec<T, M2>, Ts...>;
// another Mat of different sizes: unimplemented for SFINAE failure
template <std::size_t N1, std::size_t N2, std::size_t M1, std::size_t M2,
typename T, typename ... Ts>
struct dimMat<N1, M1, Mat<T, N2, M2>, Ts...>;
// a not-Vec, not-Mat type: continue
template <std::size_t N, std::size_t M, typename T, typename ... Ts>
struct dimMat<N, M, T, Ts...> : public dimMat<N, M, Ts...>
{ };
对于applyMH1()
两种情况:如果N
为零,那么第一个参数是一个空索引列表,那么我们有vec情况
// Vec case: the first index list is empty: call applyH2()
template <std::size_t ... Js, typename F, typename ... Args>
auto applyMH1 (std::index_sequence<> const &,
std::index_sequence<Js...> const &, F && f, Args ... as)
-> Vec<decltype(applyH2<0U>(f, as...)), sizeof...(Js)>
{ return { applyH2<Js>(f, as...)... }; }
和applyMH3()
下面是一个完整的编译示例
#include <array>
#include <iostream>
#include <type_traits>
template <typename T, std::size_t N>
class Vec;
template <typename T, std::size_t N, std::size_t M>
struct Mat;
template <std::size_t, std::size_t, typename ...>
struct dimMat;
// ground case for no Vecs and no Mats: unimplemented for SFINAE failure
template <>
struct dimMat<0U, 0U>;
// ground case with one or more Vecs and/or Mats: sizes fixed
template <std::size_t N, std::size_t M>
struct dimMat<N, M>
{
static constexpr std::size_t valN { N };
static constexpr std::size_t valM { M };
};
// first Vec: M detected
template <std::size_t M, typename T, typename ... Ts>
struct dimMat<0U, 0U, Vec<T, M>, Ts...> : public dimMat<0U, M, Ts...>
{ };
// first Mat: N and M detected
template <std::size_t N, std::size_t M, typename T, typename ... Ts>
struct dimMat<0U, 0U, Mat<T, N, M>, Ts...> : public dimMat<N, M, Ts...>
{ };
// first Mat after a correct Vect: N detected
template <std::size_t N, std::size_t M, typename T, typename ... Ts>
struct dimMat<0U, M, Mat<T, N, M>, Ts...> : public dimMat<N, M, Ts...>
{ };
// another Vec of correct size: continue
template <std::size_t N, std::size_t M, typename T, typename ... Ts>
struct dimMat<N, M, Vec<T, M>, Ts...> : public dimMat<N, M, Ts...>
{ };
// another Mat of correct sizes: continue
template <std::size_t N, std::size_t M, typename T, typename ... Ts>
struct dimMat<N, M, Mat<T, N, M>, Ts...> : public dimMat<N, M, Ts...>
{ };
// another Vec of different size: unimplemented for SFINAE failure
template <std::size_t N, std::size_t M1, std::size_t M2, typename T,
typename ... Ts>
struct dimMat<N, M1, Vec<T, M2>, Ts...>;
// another Mat of different sizes: unimplemented for SFINAE failure
template <std::size_t N1, std::size_t N2, std::size_t M1, std::size_t M2,
typename T, typename ... Ts>
struct dimMat<N1, M1, Mat<T, N2, M2>, Ts...>;
// a not-Vec, not-Mat type: continue
template <std::size_t N, std::size_t M, typename T, typename ... Ts>
struct dimMat<N, M, T, Ts...> : public dimMat<N, M, Ts...>
{ };
template <typename ... Args>
static constexpr auto dimMatN { dimMat<0U, 0U, Args...>::valN };
template <typename ... Args>
static constexpr auto dimMatM { dimMat<0U, 0U, Args...>::valM };
template <std::size_t, typename ...>
struct dimVec;
// ground case for no Vecs: unimplemented !
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 !
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 <std::size_t I, typename T, std::size_t N, std::size_t M>
constexpr auto extrV (Mat<T, N, M> const & v)
{ return 0; }
template <std::size_t I, std::size_t J, typename T,
std::size_t N, std::size_t M>
constexpr auto extrM (Mat<T, N, M> const & v)
{ return v[I][J]; }
template <std::size_t I, std::size_t J, typename T>
constexpr auto extrM (T const & v)
{ return extrV<J>(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 <typename T, std::size_t N, std::size_t M>
struct Mat
{
std::array<std::array<T, M>, N> m;
auto & operator[] (int i)
{ return m[i]; }
auto const & operator[] (int i) const
{ return m[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...); }
template <std::size_t I, std::size_t J, typename F, typename ... Args>
auto applyMH3 (F && f, Args ... as)
{ return f(extrM<I, J>(as)...); }
template <std::size_t I, std::size_t ... Js, typename F, typename ... Args>
auto applyMH2 (std::index_sequence<Js...> const &, F && f, Args ... as)
-> std::array<decltype(applyMH3<0U, 0U>(f, as...)), sizeof...(Js)>
{ return {{ applyMH3<I, Js>(f, as...)... }}; }
// Vec case: the first index list is empty: call applyH2()
template <std::size_t ... Js, typename F, typename ... Args>
auto applyMH1 (std::index_sequence<> const &,
std::index_sequence<Js...> const &, F && f, Args ... as)
-> Vec<decltype(applyH2<0U>(f, as...)), sizeof...(Js)>
{ return { applyH2<Js>(f, as...)... }; }
template <std::size_t ... Is, std::size_t ... Js, typename F,
typename ... Args>
auto applyMH1 (std::index_sequence<Is...> const &,
std::index_sequence<Js...> const & js, F && f, Args ... as)
-> Mat<decltype(applyMH3<0U, 0U>(f, as...)), sizeof...(Is), sizeof...(Js)>
{ return {{{ applyMH2<Is>(js, f, as...) ... }}}; }
template <typename F, typename ... Args, std::size_t N = dimMatN<Args...>,
std::size_t M = dimMatM<Args...>>
auto applyM (F && f, Args ... as)
{ return applyMH1(std::make_index_sequence<N>{},
std::make_index_sequence<M>{},
f, as...); }
long foo (int a, int b)
{ return a + b + 42; }
int main ()
{
Vec<int, 3U> v3;
Vec<int, 2U> v2;
Mat<int, 2U, 3U> m23;
Mat<int, 2U, 4U> m24;
auto r1 { applyM(foo, v2, v2) };
auto r2 { applyM(foo, v3, v3) };
auto r3 { applyM(foo, v3, 0) };
auto r4 { applyM(foo, v3, m23) };
auto r5 { applyM(foo, m24, 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>>{}, "!" );
static_assert( std::is_same<decltype(r4), Mat<long, 2U, 3U>>{}, "!" );
static_assert( std::is_same<decltype(r5), Mat<long, 2U, 4U>>{}, "!" );
//applyM(foo, v2, v3); // compilation error
//applyM(foo, 1, 2); // compilation error
//applyM(foo, v2, m23); // compilation error
//applyM(foo, m24, m23); // compilation error
}
#include <array>
#include <string>
#include <iostream>
template <typename T, std::size_t ...>
struct tensor;
template <typename T, std::size_t N, std::size_t ... Ns>
struct tensor<T, N, Ns...>
{
using nextT = std::conditional_t<(sizeof...(Ns) > 0U),
tensor<T, Ns...>, T>;
std::array<nextT, N> value;
auto const & operator[] (std::size_t i) const
{ return value[i]; }
auto & operator[] (std::size_t i)
{ return value[i]; }
};
// scalar case: return value
template <std::size_t ... Is, typename T>
constexpr auto extrV (std::index_sequence<Is...> const &, T const & t)
{ return t; }
// tensor case with lower dimension: skip the first requested index
template <std::size_t I0, std::size_t ... Is,
typename T, std::size_t ... Js>
constexpr auto extrV
(std::index_sequence<I0, Is...> const &, tensor<T, Js...> const & t,
std::enable_if_t<(sizeof...(Is) >= sizeof...(Js))> * = nullptr)
{ return extrV(std::index_sequence<Is...>{}, t); }
// tensor case with exact dimension: use the first requested index
template <std::size_t I0, std::size_t ... Is,
typename T, std::size_t ... Js>
constexpr auto extrV
(std::index_sequence<I0, Is...> const &, tensor<T, Js...> const & t,
std::enable_if_t<(sizeof...(Is)+1U == sizeof...(Js))> * = nullptr)
{ return extrV(std::index_sequence<Is...>{}, t[I0]); }
template <typename, typename, typename, typename = std::true_type>
struct gsHelper;
// sequences of different lengths: skipp the first index in longest
template <typename T, std::size_t I0, std::size_t ... Is, std::size_t ... Js>
struct gsHelper<T, std::index_sequence<I0, Is...>,
std::index_sequence<Js...>,
std::integral_constant<bool, (sizeof...(Is) >= sizeof...(Js))>>
: public gsHelper<T, std::index_sequence<Is...>,
std::index_sequence<Js...>>
{ };
template <typename T, typename IS>
struct gsHelper<T, IS, IS>
{ using type = T; };
template <typename, typename, bool>
struct greaterSeq;
template <typename T1, typename T2>
struct greaterSeq<T1, T2, true> : public gsHelper<T1, T1, T2>
{ };
template <typename T1, typename T2>
struct greaterSeq<T1, T2, false> : public gsHelper<T2, T2, T1>
{ };
template <typename T1, typename T2, bool B>
using greaterSeqT = typename greaterSeq<T1, T2, B>::type;
template <typename ...>
struct commonDims;
// ground case: define type as surviving parameter
template <std::size_t I0, std::size_t ... Is>
struct commonDims<std::index_sequence<I0, Is...>>
{ using type = std::index_sequence<I0, Is...>; };
// no tensor type: continue
template <typename IS, typename T0, typename ... Ts>
struct commonDims<IS, T0, Ts...> : public commonDims<IS, Ts...>
{ };
// tensor type: continue with bigger common index list (if any)
template <std::size_t ... Is, typename T, std::size_t ... Js,
typename ... Ts>
struct commonDims<std::index_sequence<Is...>, tensor<T, Js...>, Ts...>
: public commonDims<greaterSeqT<std::index_sequence<Is...>,
std::index_sequence<Js...>,
(sizeof...(Is) > sizeof...(Js))>, Ts...>
{ };
template <typename ... Ts>
using commonDimsT = typename commonDims<std::index_sequence<>, Ts...>::type;
template <typename IS, typename F, typename ... Args>
auto call (IS const & is, F && f, Args const & ... as)
{ return f(extrV(is, as)...); }
template <std::size_t ... Is, std::size_t ... Js, std::size_t ... Ks,
typename F, typename ... Args>
auto applyH2 (std::index_sequence<Is...> const &,
std::index_sequence<Js...> const &,
std::index_sequence<Ks...> const & ks,
F && f, Args const & ... as)
-> tensor<
decltype(call(std::index_sequence<(Is, 0U)..., 0U, (Ks, 0U)...>{},
f, as...)), sizeof...(Js), Ks...>
{ return {{{ applyH1(std::index_sequence<Is..., Js>{},
ks, f, as...) ... }}}; }
template <typename IS, typename F, typename ... Args>
auto applyH1 (IS const & is, std::index_sequence<> const &,
F && f, Args const & ... as)
{ return call(is, f, as...); }
template <typename IS, std::size_t J0, std::size_t ... Js,
typename F, typename ... Args>
auto applyH1 (IS const & is, std::index_sequence<J0, Js...> const &,
F && f, Args const & ... as)
{ return applyH2(is, std::make_index_sequence<J0>{},
std::index_sequence<Js...>{}, f, as...); }
template <typename F, typename ... Args, typename IS = commonDimsT<Args...>>
auto apply (F && f, Args const & ... as)
{ return applyH1(std::index_sequence<>{}, IS{}, f, as...); }
long foo (int a, int b)
{ return a + b + 42; }
int main ()
{
tensor<int, 2, 3, 4, 5> t0;
t0[0][0][0][0] = 1;
using t1 = commonDimsT<tensor<int, 1>, long, tensor<long, 3, 2, 1>, int>;
static_assert(std::is_same<t1, std::index_sequence<3, 2, 1>>{}, "!");
auto r1 { apply(foo, tensor<int, 3, 2, 1>{}, 0) };
auto r2 { apply(foo, tensor<int, 3, 2, 1>{}, tensor<int, 3, 2, 1>{}) };
auto r3 { apply(foo, tensor<int, 3, 2, 1>{}, tensor<int, 2, 1>{}) };
auto r4 { apply(foo, tensor<int, 3, 2, 1>{}, tensor<int, 1>{}) };
auto r5 { apply(foo, 0, tensor<int, 1>{}) };
static_assert(std::is_same<decltype(r1), tensor<long, 3, 2, 1>>{}, "!");
static_assert(std::is_same<decltype(r2), tensor<long, 3, 2, 1>>{}, "!");
static_assert(std::is_same<decltype(r3), tensor<long, 3, 2, 1>>{}, "!");
static_assert(std::is_same<decltype(r4), tensor<long, 3, 2, 1>>{}, "!");
static_assert(std::is_same<decltype(r5), tensor<long, 1>>{}, "!");
// compilation errors (no common tensor)
//apply(foo, 0, 0);
//apply(foo, tensor<int, 3, 2, 1>{}, tensor<int, 2>{});
}
template <std::size_t I, std::size_t J, typename T,
std::size_t N, std::size_t M>
constexpr auto extrM (Mat<T, N, M> const & v)
{ return v[I][J]; }
template <std::size_t I, std::size_t J, typename T>
constexpr auto extrM (T const & v)
{ return extrV<J>(v); }
#include <array>
#include <iostream>
#include <type_traits>
template <typename T, std::size_t N>
class Vec;
template <typename T, std::size_t N, std::size_t M>
struct Mat;
template <std::size_t, std::size_t, typename ...>
struct dimMat;
// ground case for no Vecs and no Mats: unimplemented for SFINAE failure
template <>
struct dimMat<0U, 0U>;
// ground case with one or more Vecs and/or Mats: sizes fixed
template <std::size_t N, std::size_t M>
struct dimMat<N, M>
{
static constexpr std::size_t valN { N };
static constexpr std::size_t valM { M };
};
// first Vec: M detected
template <std::size_t M, typename T, typename ... Ts>
struct dimMat<0U, 0U, Vec<T, M>, Ts...> : public dimMat<0U, M, Ts...>
{ };
// first Mat: N and M detected
template <std::size_t N, std::size_t M, typename T, typename ... Ts>
struct dimMat<0U, 0U, Mat<T, N, M>, Ts...> : public dimMat<N, M, Ts...>
{ };
// first Mat after a correct Vect: N detected
template <std::size_t N, std::size_t M, typename T, typename ... Ts>
struct dimMat<0U, M, Mat<T, N, M>, Ts...> : public dimMat<N, M, Ts...>
{ };
// another Vec of correct size: continue
template <std::size_t N, std::size_t M, typename T, typename ... Ts>
struct dimMat<N, M, Vec<T, M>, Ts...> : public dimMat<N, M, Ts...>
{ };
// another Mat of correct sizes: continue
template <std::size_t N, std::size_t M, typename T, typename ... Ts>
struct dimMat<N, M, Mat<T, N, M>, Ts...> : public dimMat<N, M, Ts...>
{ };
// another Vec of different size: unimplemented for SFINAE failure
template <std::size_t N, std::size_t M1, std::size_t M2, typename T,
typename ... Ts>
struct dimMat<N, M1, Vec<T, M2>, Ts...>;
// another Mat of different sizes: unimplemented for SFINAE failure
template <std::size_t N1, std::size_t N2, std::size_t M1, std::size_t M2,
typename T, typename ... Ts>
struct dimMat<N1, M1, Mat<T, N2, M2>, Ts...>;
// a not-Vec, not-Mat type: continue
template <std::size_t N, std::size_t M, typename T, typename ... Ts>
struct dimMat<N, M, T, Ts...> : public dimMat<N, M, Ts...>
{ };
template <typename ... Args>
static constexpr auto dimMatN { dimMat<0U, 0U, Args...>::valN };
template <typename ... Args>
static constexpr auto dimMatM { dimMat<0U, 0U, Args...>::valM };
template <std::size_t, typename ...>
struct dimVec;
// ground case for no Vecs: unimplemented !
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 !
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 <std::size_t I, typename T, std::size_t N, std::size_t M>
constexpr auto extrV (Mat<T, N, M> const & v)
{ return 0; }
template <std::size_t I, std::size_t J, typename T,
std::size_t N, std::size_t M>
constexpr auto extrM (Mat<T, N, M> const & v)
{ return v[I][J]; }
template <std::size_t I, std::size_t J, typename T>
constexpr auto extrM (T const & v)
{ return extrV<J>(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 <typename T, std::size_t N, std::size_t M>
struct Mat
{
std::array<std::array<T, M>, N> m;
auto & operator[] (int i)
{ return m[i]; }
auto const & operator[] (int i) const
{ return m[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...); }
template <std::size_t I, std::size_t J, typename F, typename ... Args>
auto applyMH3 (F && f, Args ... as)
{ return f(extrM<I, J>(as)...); }
template <std::size_t I, std::size_t ... Js, typename F, typename ... Args>
auto applyMH2 (std::index_sequence<Js...> const &, F && f, Args ... as)
-> std::array<decltype(applyMH3<0U, 0U>(f, as...)), sizeof...(Js)>
{ return {{ applyMH3<I, Js>(f, as...)... }}; }
// Vec case: the first index list is empty: call applyH2()
template <std::size_t ... Js, typename F, typename ... Args>
auto applyMH1 (std::index_sequence<> const &,
std::index_sequence<Js...> const &, F && f, Args ... as)
-> Vec<decltype(applyH2<0U>(f, as...)), sizeof...(Js)>
{ return { applyH2<Js>(f, as...)... }; }
template <std::size_t ... Is, std::size_t ... Js, typename F,
typename ... Args>
auto applyMH1 (std::index_sequence<Is...> const &,
std::index_sequence<Js...> const & js, F && f, Args ... as)
-> Mat<decltype(applyMH3<0U, 0U>(f, as...)), sizeof...(Is), sizeof...(Js)>
{ return {{{ applyMH2<Is>(js, f, as...) ... }}}; }
template <typename F, typename ... Args, std::size_t N = dimMatN<Args...>,
std::size_t M = dimMatM<Args...>>
auto applyM (F && f, Args ... as)
{ return applyMH1(std::make_index_sequence<N>{},
std::make_index_sequence<M>{},
f, as...); }
long foo (int a, int b)
{ return a + b + 42; }
int main ()
{
Vec<int, 3U> v3;
Vec<int, 2U> v2;
Mat<int, 2U, 3U> m23;
Mat<int, 2U, 4U> m24;
auto r1 { applyM(foo, v2, v2) };
auto r2 { applyM(foo, v3, v3) };
auto r3 { applyM(foo, v3, 0) };
auto r4 { applyM(foo, v3, m23) };
auto r5 { applyM(foo, m24, 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>>{}, "!" );
static_assert( std::is_same<decltype(r4), Mat<long, 2U, 3U>>{}, "!" );
static_assert( std::is_same<decltype(r5), Mat<long, 2U, 4U>>{}, "!" );
//applyM(foo, v2, v3); // compilation error
//applyM(foo, 1, 2); // compilation error
//applyM(foo, v2, m23); // compilation error
//applyM(foo, m24, m23); // compilation error
}
template <typename T, std::size_t ...>
struct tensor;
template <typename T, std::size_t N, std::size_t ... Ns>
struct tensor<T, N, Ns...>
{
using nextT = std::conditional_t<(sizeof...(Ns) > 0U),
tensor<T, Ns...>, T>;
std::array<nextT, N> value;
auto const & operator[] (std::size_t i) const
{ return value[i]; }
auto & operator[] (std::size_t i)
{ return value[i]; }
};
// scalar case: return value
template <std::size_t ... Is, typename T>
constexpr auto extrV (std::index_sequence<Is...> const &, T const & t)
{ return t; }
// tensor case with lower dimension: skip the first requested index
template <std::size_t I0, std::size_t ... Is,
typename T, std::size_t ... Js>
constexpr auto extrV
(std::index_sequence<I0, Is...> const &, tensor<T, Js...> const & t,
std::enable_if_t<(sizeof...(Is) >= sizeof...(Js))> * = nullptr)
{ return extrV(std::index_sequence<Is...>{}, t); }
// tensor case with exact dimension: use the first requested index
template <std::size_t I0, std::size_t ... Is,
typename T, std::size_t ... Js>
constexpr auto extrV
(std::index_sequence<I0, Is...> const &, tensor<T, Js...> const & t,
std::enable_if_t<(sizeof...(Is)+1U == sizeof...(Js))> * = nullptr)
{ return extrV(std::index_sequence<Is...>{}, t[I0]); }
template <typename ...>
struct commonDims;
// ground case: define type as surviving parameter
template <std::size_t I0, std::size_t ... Is>
struct commonDims<std::index_sequence<I0, Is...>>
{ using type = std::index_sequence<I0, Is...>; };
// no tensor type: continue
template <typename IS, typename T0, typename ... Ts>
struct commonDims<IS, T0, Ts...> : public commonDims<IS, Ts...>
{ };
// tensor type: continue with bigger common index list (if any)
template <std::size_t ... Is, typename T, std::size_t ... Js,
typename ... Ts>
struct commonDims<std::index_sequence<Is...>, tensor<T, Js...>, Ts...>
: public commonDims<greaterSeqT<std::index_sequence<Is...>,
std::index_sequence<Js...>,
(sizeof...(Is) > sizeof...(Js))>, Ts...>
{ };
template <typename ... Ts>
using commonDimsT = typename commonDims<std::index_sequence<>, Ts...>::type;
template <typename, typename, bool>
struct greaterSeq;
template <typename T1, typename T2>
struct greaterSeq<T1, T2, true> : public gsHelper<T1, T1, T2>
{ };
template <typename T1, typename T2>
struct greaterSeq<T1, T2, false> : public gsHelper<T2, T2, T1>
{ };
template <typename T1, typename T2, bool B>
using greaterSeqT = typename greaterSeq<T1, T2, B>::type;
template <typename, typename, typename, typename = std::true_type>
struct gsHelper;
// sequences of different lengths: skipp the first index in longest
template <typename T, std::size_t I0, std::size_t ... Is, std::size_t ... Js>
struct gsHelper<T, std::index_sequence<I0, Is...>,
std::index_sequence<Js...>,
std::integral_constant<bool, (sizeof...(Is) >= sizeof...(Js))>>
: public gsHelper<T, std::index_sequence<Is...>,
std::index_sequence<Js...>>
{ };
template <typename T, typename IS>
struct gsHelper<T, IS, IS>
{ using type = T; };
template <typename F, typename ... Args, typename IS = commonDimsT<Args...>>
auto apply (F && f, Args const & ... as)
{ return applyH1(std::index_sequence<>{}, IS{}, f, as...); }
template <std::size_t ... Is, std::size_t ... Js, std::size_t ... Ks,
typename F, typename ... Args>
auto applyH2 (std::index_sequence<Is...> const &,
std::index_sequence<Js...> const &,
std::index_sequence<Ks...> const & ks,
F && f, Args const & ... as)
-> tensor<
decltype(call(std::index_sequence<(Is, 0U)..., 0U, (Ks, 0U)...>{},
f, as...)), sizeof...(Js), Ks...>
{ return {{{ applyH1(std::index_sequence<Is..., Js>{},
ks, f, as...) ... }}}; }
template <typename IS, typename F, typename ... Args>
auto applyH1 (IS const & is, std::index_sequence<> const &,
F && f, Args const & ... as)
{ return call(is, f, as...); }
template <typename IS, std::size_t J0, std::size_t ... Js,
typename F, typename ... Args>
auto applyH1 (IS const & is, std::index_sequence<J0, Js...> const &,
F && f, Args const & ... as)
{ return applyH2(is, std::make_index_sequence<J0>{},
std::index_sequence<Js...>{}, f, as...); }
template <typename IS, typename F, typename ... Args>
auto call (IS const & is, F && f, Args const & ... as)
{ return f(extrV(is, as)...); }
#include <array>
#include <string>
#include <iostream>
template <typename T, std::size_t ...>
struct tensor;
template <typename T, std::size_t N, std::size_t ... Ns>
struct tensor<T, N, Ns...>
{
using nextT = std::conditional_t<(sizeof...(Ns) > 0U),
tensor<T, Ns...>, T>;
std::array<nextT, N> value;
auto const & operator[] (std::size_t i) const
{ return value[i]; }
auto & operator[] (std::size_t i)
{ return value[i]; }
};
// scalar case: return value
template <std::size_t ... Is, typename T>
constexpr auto extrV (std::index_sequence<Is...> const &, T const & t)
{ return t; }
// tensor case with lower dimension: skip the first requested index
template <std::size_t I0, std::size_t ... Is,
typename T, std::size_t ... Js>
constexpr auto extrV
(std::index_sequence<I0, Is...> const &, tensor<T, Js...> const & t,
std::enable_if_t<(sizeof...(Is) >= sizeof...(Js))> * = nullptr)
{ return extrV(std::index_sequence<Is...>{}, t); }
// tensor case with exact dimension: use the first requested index
template <std::size_t I0, std::size_t ... Is,
typename T, std::size_t ... Js>
constexpr auto extrV
(std::index_sequence<I0, Is...> const &, tensor<T, Js...> const & t,
std::enable_if_t<(sizeof...(Is)+1U == sizeof...(Js))> * = nullptr)
{ return extrV(std::index_sequence<Is...>{}, t[I0]); }
template <typename, typename, typename, typename = std::true_type>
struct gsHelper;
// sequences of different lengths: skipp the first index in longest
template <typename T, std::size_t I0, std::size_t ... Is, std::size_t ... Js>
struct gsHelper<T, std::index_sequence<I0, Is...>,
std::index_sequence<Js...>,
std::integral_constant<bool, (sizeof...(Is) >= sizeof...(Js))>>
: public gsHelper<T, std::index_sequence<Is...>,
std::index_sequence<Js...>>
{ };
template <typename T, typename IS>
struct gsHelper<T, IS, IS>
{ using type = T; };
template <typename, typename, bool>
struct greaterSeq;
template <typename T1, typename T2>
struct greaterSeq<T1, T2, true> : public gsHelper<T1, T1, T2>
{ };
template <typename T1, typename T2>
struct greaterSeq<T1, T2, false> : public gsHelper<T2, T2, T1>
{ };
template <typename T1, typename T2, bool B>
using greaterSeqT = typename greaterSeq<T1, T2, B>::type;
template <typename ...>
struct commonDims;
// ground case: define type as surviving parameter
template <std::size_t I0, std::size_t ... Is>
struct commonDims<std::index_sequence<I0, Is...>>
{ using type = std::index_sequence<I0, Is...>; };
// no tensor type: continue
template <typename IS, typename T0, typename ... Ts>
struct commonDims<IS, T0, Ts...> : public commonDims<IS, Ts...>
{ };
// tensor type: continue with bigger common index list (if any)
template <std::size_t ... Is, typename T, std::size_t ... Js,
typename ... Ts>
struct commonDims<std::index_sequence<Is...>, tensor<T, Js...>, Ts...>
: public commonDims<greaterSeqT<std::index_sequence<Is...>,
std::index_sequence<Js...>,
(sizeof...(Is) > sizeof...(Js))>, Ts...>
{ };
template <typename ... Ts>
using commonDimsT = typename commonDims<std::index_sequence<>, Ts...>::type;
template <typename IS, typename F, typename ... Args>
auto call (IS const & is, F && f, Args const & ... as)
{ return f(extrV(is, as)...); }
template <std::size_t ... Is, std::size_t ... Js, std::size_t ... Ks,
typename F, typename ... Args>
auto applyH2 (std::index_sequence<Is...> const &,
std::index_sequence<Js...> const &,
std::index_sequence<Ks...> const & ks,
F && f, Args const & ... as)
-> tensor<
decltype(call(std::index_sequence<(Is, 0U)..., 0U, (Ks, 0U)...>{},
f, as...)), sizeof...(Js), Ks...>
{ return {{{ applyH1(std::index_sequence<Is..., Js>{},
ks, f, as...) ... }}}; }
template <typename IS, typename F, typename ... Args>
auto applyH1 (IS const & is, std::index_sequence<> const &,
F && f, Args const & ... as)
{ return call(is, f, as...); }
template <typename IS, std::size_t J0, std::size_t ... Js,
typename F, typename ... Args>
auto applyH1 (IS const & is, std::index_sequence<J0, Js...> const &,
F && f, Args const & ... as)
{ return applyH2(is, std::make_index_sequence<J0>{},
std::index_sequence<Js...>{}, f, as...); }
template <typename F, typename ... Args, typename IS = commonDimsT<Args...>>
auto apply (F && f, Args const & ... as)
{ return applyH1(std::index_sequence<>{}, IS{}, f, as...); }
long foo (int a, int b)
{ return a + b + 42; }
int main ()
{
tensor<int, 2, 3, 4, 5> t0;
t0[0][0][0][0] = 1;
using t1 = commonDimsT<tensor<int, 1>, long, tensor<long, 3, 2, 1>, int>;
static_assert(std::is_same<t1, std::index_sequence<3, 2, 1>>{}, "!");
auto r1 { apply(foo, tensor<int, 3, 2, 1>{}, 0) };
auto r2 { apply(foo, tensor<int, 3, 2, 1>{}, tensor<int, 3, 2, 1>{}) };
auto r3 { apply(foo, tensor<int, 3, 2, 1>{}, tensor<int, 2, 1>{}) };
auto r4 { apply(foo, tensor<int, 3, 2, 1>{}, tensor<int, 1>{}) };
auto r5 { apply(foo, 0, tensor<int, 1>{}) };
static_assert(std::is_same<decltype(r1), tensor<long, 3, 2, 1>>{}, "!");
static_assert(std::is_same<decltype(r2), tensor<long, 3, 2, 1>>{}, "!");
static_assert(std::is_same<decltype(r3), tensor<long, 3, 2, 1>>{}, "!");
static_assert(std::is_same<decltype(r4), tensor<long, 3, 2, 1>>{}, "!");
static_assert(std::is_same<decltype(r5), tensor<long, 1>>{}, "!");
// compilation errors (no common tensor)
//apply(foo, 0, 0);
//apply(foo, tensor<int, 3, 2, 1>{}, tensor<int, 2>{});
}