使用可变模板参数的构造函数和函数
Constructor and functions using variadic templated parameters
我想写一个class,它由多个维度模板化:
namespace detail {
enum class enabler {};
}
template<size_t dim>
class templateClass
{
public:
template<class... DimArgs, typename std::enable_if<sizeof...(DimArgs)==dim, detail::enabler>::type...>
templateClass(DimArgs... dimensions) {
// Use integers passed to the constructor, one for each dimension
}
};
detail::enabler
枚举位于 almost-static-if link。这里它被用作第二个参数包,允许传递 0 个参数。作用域枚举没有成员,不能(?)被意外传递。
他们还使用 using
声明来吞下一些 typename
等部分,但我已经输入完整内容以避免在那里阅读它。
如何使用我通过的dimensions
parameter pack?
class效果很好,例如:
templateClass<2> temp(5, 2); // works
templateClass<3> temp(5, 2, 4); // works
templateClass<1> temp(5,2); // would give compile-time error
但也许我已经有了一个(或几个)坏主意我应该use/do在这里?
编辑:
我发现的一种解决方案是创建 std::initializer_list
。我可以使用 int
或 size_t
class 来创建它,这在这里效果很好。但是,如果我不知道传递的参数的类型(例如,因为我的函数可以同时使用 int
s 和 double
s,用于其他目的),是否有更好的方法比:
std::initializer_list<int> list{dimensions...};
for (int i : list) {
std::cout << "i = " << i << std::endl;
}
完整的工作示例:
Mesh.H:
#ifndef MESH_H
#define MESH_H
#include <type_traits>
#include <initializer_list>
#include <iostream>
namespace detail {
enum class enabler {};
}
template <bool Condition>
using EnableIf =
typename std::enable_if<Condition, detail::enabler>::type;
template<size_t meshDim>
class Mesh
{
public:
template<class... DimArgs, EnableIf<sizeof...(DimArgs)==meshDim>...>
Mesh(DimArgs... dimensions){
std::initializer_list<int> list{dimensions...};
for (int i : list) {
std::cout << "i = " << i << std::endl;
}
}
};
#endif // MESH_H
main.cpp:
#include <iostream>
#include "Mesh.H"
int main()
{
Mesh<2> mesh(5, 2);
return 0;
}
使用 g++ --std=c++11 main.cpp
编译
可以通过将参数包放入元组来索引参数包:
using T1 = std::tuple_element<0, std::tuple<DimArgs...>>; // Any index should work, not just 0
不过,这并不能完全解决可能的数字提升或缩小问题。我认为相当于 decltype(tuple_sum(dimensions...))
的东西可以解决问题(前提是您可以假设它们是数字)。它可能看起来像这样(未经测试):
template<typename T>
constexpr T tuple_sum(T n) {return n;}
template<typename T, typename... Rest>
constexpr auto tuple_sum(T first, Rest... rest) {
return first + tuple_sum(rest...);
}
为了使代码可移植,您不应使用匿名模板参数。
这是使用 MinGW g++ 5.1 和 Visual C++ 2015 编译的代码:
#include <utility> // std::enable_if
#define IS_UNUSED( a ) (void) a; struct a
template< int dim >
class Tensor
{
public:
template< class... Args
, class Enabled_ = typename std::enable_if< sizeof...(Args) == dim, void >::type
>
Tensor( Args... args )
{
int const dimensions[] = { args... };
IS_UNUSED( dimensions );
}
};
auto main() -> int
{
Tensor<2> tempA(5, 2); // works
Tensor<3> tempB(5, 2, 4); // works
#ifdef FAIL
Tensor<1> temp(5,2); // would give compile-time error
#endif
}
我想写一个class,它由多个维度模板化:
namespace detail {
enum class enabler {};
}
template<size_t dim>
class templateClass
{
public:
template<class... DimArgs, typename std::enable_if<sizeof...(DimArgs)==dim, detail::enabler>::type...>
templateClass(DimArgs... dimensions) {
// Use integers passed to the constructor, one for each dimension
}
};
detail::enabler
枚举位于 almost-static-if link。这里它被用作第二个参数包,允许传递 0 个参数。作用域枚举没有成员,不能(?)被意外传递。
他们还使用 using
声明来吞下一些 typename
等部分,但我已经输入完整内容以避免在那里阅读它。
如何使用我通过的dimensions
parameter pack?
class效果很好,例如:
templateClass<2> temp(5, 2); // works
templateClass<3> temp(5, 2, 4); // works
templateClass<1> temp(5,2); // would give compile-time error
但也许我已经有了一个(或几个)坏主意我应该use/do在这里?
编辑:
我发现的一种解决方案是创建 std::initializer_list
。我可以使用 int
或 size_t
class 来创建它,这在这里效果很好。但是,如果我不知道传递的参数的类型(例如,因为我的函数可以同时使用 int
s 和 double
s,用于其他目的),是否有更好的方法比:
std::initializer_list<int> list{dimensions...};
for (int i : list) {
std::cout << "i = " << i << std::endl;
}
完整的工作示例:
Mesh.H:
#ifndef MESH_H
#define MESH_H
#include <type_traits>
#include <initializer_list>
#include <iostream>
namespace detail {
enum class enabler {};
}
template <bool Condition>
using EnableIf =
typename std::enable_if<Condition, detail::enabler>::type;
template<size_t meshDim>
class Mesh
{
public:
template<class... DimArgs, EnableIf<sizeof...(DimArgs)==meshDim>...>
Mesh(DimArgs... dimensions){
std::initializer_list<int> list{dimensions...};
for (int i : list) {
std::cout << "i = " << i << std::endl;
}
}
};
#endif // MESH_H
main.cpp:
#include <iostream>
#include "Mesh.H"
int main()
{
Mesh<2> mesh(5, 2);
return 0;
}
使用 g++ --std=c++11 main.cpp
可以通过将参数包放入元组来索引参数包:
using T1 = std::tuple_element<0, std::tuple<DimArgs...>>; // Any index should work, not just 0
不过,这并不能完全解决可能的数字提升或缩小问题。我认为相当于 decltype(tuple_sum(dimensions...))
的东西可以解决问题(前提是您可以假设它们是数字)。它可能看起来像这样(未经测试):
template<typename T>
constexpr T tuple_sum(T n) {return n;}
template<typename T, typename... Rest>
constexpr auto tuple_sum(T first, Rest... rest) {
return first + tuple_sum(rest...);
}
为了使代码可移植,您不应使用匿名模板参数。
这是使用 MinGW g++ 5.1 和 Visual C++ 2015 编译的代码:
#include <utility> // std::enable_if
#define IS_UNUSED( a ) (void) a; struct a
template< int dim >
class Tensor
{
public:
template< class... Args
, class Enabled_ = typename std::enable_if< sizeof...(Args) == dim, void >::type
>
Tensor( Args... args )
{
int const dimensions[] = { args... };
IS_UNUSED( dimensions );
}
};
auto main() -> int
{
Tensor<2> tempA(5, 2); // works
Tensor<3> tempB(5, 2, 4); // works
#ifdef FAIL
Tensor<1> temp(5,2); // would give compile-time error
#endif
}