类型依赖于可变参数模板的类
Class with types dependant on variadic templating
我最近看了一个视频,它启发了我编写自己的神经网络系统,我想让网络中的节点数量是可调的。
起初,我通过解析节点数数组在运行时实现了这一目标,但我想知道是否可以在编译时执行此操作。这是我希望完成的那种事情的一个例子。
template<int FirstNodes, int SecondNodes, int... OtherNodes>
class Net
{
tuple<Eigen::Matrix<float, FirstNodes, SecondNodes>, ...> m_weights;
// More matricies with the values from the OtherNodes
};
作为更详细的示例,Net<784, 16, 16, 10> n;
n.m_weight应该具有类型
tuple<Eigen::Matrix<float, 784, 16>,
Eigen::Matrix<float, 16, 16>,
Eigen::Matrix<float, 16, 10>>
根据我对C++和constexpr的了解,这应该是可能的。
我应该补充一点,我能够做到
template<int FirstNodes, int SecondNodes, int... OtherNodes>
class Net
{
public:
Net()
{
auto nodes = {FirstNodes, SecondNodes, OtherNodes...};
auto i = nodes.begin();
do
{
// Eigen::Matrix<float, Dynamic, Dynamic>
Eigen::MatrixXf m(*(i++), *i);
} while (i+1 != nodes.end());
}
};
但是我只是再次使用动态矩阵,这不是我所希望的。
任何建议或工作实例将不胜感激。
你想要某种类型转换,给定一个N
整数列表,返回N - 1
矩阵的tuple
。下面是 C++17 解决方案:
template <int A, int B, int... Is>
auto make_matrix_tuple()
{
if constexpr(sizeof...(Is) == 0)
{
return std::tuple<Eigen::Matrix<float, A, B>>{};
}
else
{
return std::tuple_cat(make_matrix_tuple<A, B>(),
make_matrix_tuple<B, Is...>());
}
}
魔杖盒上的现场示例
在 C++11 中,可以递归方式实现此类型转换:
template <int... Is>
struct matrix_tuple_helper;
template <int A, int B, int... Rest>
struct matrix_tuple_helper<A, B, Rest...>
{
using curr_matrix = Eigen::Matrix<float, A, B>;
using type =
decltype(
std::tuple_cat(
std::tuple<curr_matrix>{},
typename matrix_tuple_helper<B, Rest...>::type{}
)
);
};
template <int A, int B>
struct matrix_tuple_helper<A, B>
{
using curr_matrix = Eigen::Matrix<float, A, B>;
using type = std::tuple<curr_matrix>;
};
template <int... Is>
using matrix_tuple = typename matrix_tuple_helper<Is...>::type;
C++14方法:
struct matrix_tuple_maker
{
template <int A, int B, int C, int... Is>
static auto get()
{
return std::tuple_cat(get<A, B>(), get<B, C, Is...>());
}
template <int A, int B>
static auto get()
{
return std::tuple<Eigen::Matrix<float, A, B>>{};
}
};
static_assert(std::is_same_v<
decltype(matrix_tuple_maker::get<784, 16, 16, 10>()),
std::tuple<Eigen::Matrix<float, 784, 16>,
Eigen::Matrix<float, 16, 16>,
Eigen::Matrix<float, 16, 10>>
>);
在我看来,您需要两个整数列表,相位为 1。
如果定义一个简单的模板整数容器(在 C++14 中,您可以使用 std::integer_sequence
)
template <int...>
struct iList
{ };
您可以按如下方式定义基类(抱歉:使用 foo
而不是 Eigen::Matrix
)
template <typename, typename, typename = std::tuple<>>
struct NetBase;
// avoid the first couple
template <int ... Is, int J0, int ... Js>
struct NetBase<iList<0, Is...>, iList<J0, Js...>, std::tuple<>>
: NetBase<iList<Is...>, iList<Js...>, std::tuple<>>
{ };
// intermediate case
template <int I0, int ... Is, int J0, int ... Js, typename ... Ts>
struct NetBase<iList<I0, Is...>, iList<J0, Js...>, std::tuple<Ts...>>
: NetBase<iList<Is...>, iList<Js...>,
std::tuple<Ts..., foo<float, I0, J0>>>
{ };
// avoid the last couple and terminate
template <int I0, typename ... Ts>
struct NetBase<iList<I0>, iList<0>, std::tuple<Ts...>>
{ using type = std::tuple<Ts...>; };
Net
简单地成为(观察整数列表的异相耦合)
template <int F, int S, int... Os>
struct Net : NetBase<iList<0, F, S, Os...>, iList<F, S, Os..., 0>>
{ };
以下是完整的编译示例
#include <tuple>
template <int...>
struct iList
{ };
template <typename, int, int>
struct foo
{ };
template <typename, typename, typename = std::tuple<>>
struct NetBase;
// avoid the first couple
template <int ... Is, int J0, int ... Js>
struct NetBase<iList<0, Is...>, iList<J0, Js...>, std::tuple<>>
: NetBase<iList<Is...>, iList<Js...>, std::tuple<>>
{ };
// intermediate case
template <int I0, int ... Is, int J0, int ... Js, typename ... Ts>
struct NetBase<iList<I0, Is...>, iList<J0, Js...>, std::tuple<Ts...>>
: NetBase<iList<Is...>, iList<Js...>,
std::tuple<Ts..., foo<float, I0, J0>>>
{ };
// avoid the last couple and terminate
template <int I0, typename ... Ts>
struct NetBase<iList<I0>, iList<0>, std::tuple<Ts...>>
{ using type = std::tuple<Ts...>; };
template <int F, int S, int... Os>
struct Net : NetBase<iList<0, F, S, Os...>, iList<F, S, Os..., 0>>
{ };
int main()
{
static_assert(std::is_same<
typename Net<784, 16, 16, 10>::type,
std::tuple<foo<float, 784, 16>, foo<float, 16, 16>,
foo<float, 16, 10>>>{}, "!");
}
这是另一个 C++14 解决方案。我认为它值得发布,因为它是非递归且可读的。
#include <tuple>
#include <utility>
template<class, int, int> struct Matrix {};
template<int... matsizes, std::size_t... matinds>
constexpr auto make_net(
std::integer_sequence<int, matsizes...>,
std::index_sequence<matinds...>
) {
constexpr int sizes[] = {matsizes...};
return std::tuple< Matrix<float, sizes[matinds], sizes[1+matinds]>... >{};
}
template<int... matsizes>
constexpr auto make_net(
std::integer_sequence<int, matsizes...> sizes
) {
static_assert(sizes.size() >= 2, "");
constexpr auto number_of_mats = sizes.size() - 1;
return make_net(sizes, std::make_index_sequence<number_of_mats>{});
}
int main () {
auto net = make_net(std::integer_sequence<int, 784, 16, 16, 10>{});
using Net = decltype(net);
static_assert(
std::is_same<
std::tuple<
Matrix<float, 784, 16>,
Matrix<float, 16, 16>,
Matrix<float, 16, 10>
>,
Net
>{}, ""
);
return 0;
}
相关文章:
- 类成员函数参数列表是否可以依赖于模板参数?
- 如何定义依赖于参数包转换的函数的返回类型
- C++ 使函数调用依赖于模板参数
- 如何初始化依赖于先前条目的可变参数模板?
- 如何修复"没有依赖于模板参数的参数'glGenVertexArrays'......"C++ 中的错误
- 运算符<<依赖于参数的查找不在全局命名空间中查找
- 依赖于其他模板参数的模板参数
- 使用不依赖于方法模板参数的enable_if
- 如何定义具有依赖于符号调试的参数的函数
- 如何让成员函数实现依赖于类的模板参数?
- 如何避免参数数量依赖于条件的调用分支?
- 为什么在这种情况下不考虑依赖于参数的查找?
- 如何定义依赖于模板参数的类型定义
- 类型依赖于可变参数模板的类
- C++是否可以创建依赖于单个构造函数参数的派生类而不是bass类
- 我如何避免使用依赖于参数的查找明确专门化模板化功能
- 为什么默认参数不能依赖于非默认参数?
- 为什么在语句"std::cout << std::endl;"中使用时需要命名空间限定,给定依赖于参数的查找?
- C++ 错误:"没有依赖于模板参数的'setw'参数
- 依赖于模板参数的范围查找