【问题标题】:variadic templates same number of function arguments as in class可变参数模板与类中相同数量的函数参数
【发布时间】:2015-01-02 04:49:15
【问题描述】:

如何定义方法签名,使其接受与可变参数模板类定义相同数量的参数?例如如何定义一个数组类:

template<typename T, int... shape>
class Array
{
public:
    T& operator () (???);
};

所以你可以这样称呼它:

Array<int, 3, 4, 5> a;
a(1, 2, 3) = 2;

【问题讨论】:

  • 我认为这应该可行:T&amp; operator()(decltype(shape)... args);
  • @0x499602D2 概括为:T&amp; operator()(decltype(shape, X())... args); 用于更改类型。
  • @Deduplicator 确实如此。但我以为他想要int
  • 太好了,所有方法都有效,谢谢大家!
  • 如果您只是在寻找std::array 的多维版本,您可以使用variadic array alias trick 为自己节省一些工作。

标签: c++ templates c++11 variadic-templates


【解决方案1】:
template<class T, int...Shape>
class Array {
  template<int>using index_t=int; // can change this
public:
  T& operator()(index_t<Shape>... is);
};

或:

template<class T, int...Shape>
class Array {
public:
  T& operator()(decltype(Shape)... is);
};

或:

template<class T, int...Shape>
class Array {
public:
  T& operator()(decltype(Shape, int())... is);
};

如果您希望能够将参数的类型更改为不同于Shape

我发现decltypeusing 更难理解,特别是如果您想将参数的类型更改为不同于int

另一种方法:

template<class T, int...Shape>
class Array {
public:
  template<class...Args,class=typename std::enable_if<sizeof...(Args)==sizeof...(Shape)>::type>
  T& operator()(Args&&... is);
};

使用 SFINAE。但是,它并不强制 Args 是整数类型。如果我们愿意,我们可以添加另一个子句(例如,所有 Args 都可以转换为 int)。

另一种方法是让您的operator() 获取一组值,例如std::array&lt;sizeof...(Shape), int&gt;。来电者必须:

Array<double, 3,2,1> arr;
arr({0,0,0});

使用一组{}s。

最后的方法是:

template<class T, int...Shape>
class Array {
public:
  template<class...Args>
  auto operator()(Args&&... is) {
    static_assert( sizeof...(Args)==sizeof...(Shapes), "wrong number of array indexes" );
  }
};

我们接受任何东西,然后如果参数数量错误则生成错误。这会产生非常干净的错误,但不会进行正确的 SFINAE 运算符重载。

我会推荐标签分派,但我看不出有什么方法可以让它比 SFINAE 解决方案更干净,额外的decltype 和所有,或者比static_assert 版本更好的错误消息.

【讨论】:

  • 看来检查int转换是多余的,Array a; a((char)1, (short)2, 2.0f);无论如何都可以。
  • @DikobrAz 担心Array&lt;int, 1,2,3&gt; a; a( "hello", "world", 3 ); 也会起作用,然后在operator() 的主体内中断,这不太理想。如果您有其他元编程代码询问“您可以使用这些参数调用吗”,您最好不要对此撒谎。
  • 人们不应忽视,不必假设、查找或仍然记住的每一点都意味着更多的脑力可用于其他事情。这让我更喜欢decltype。 (虽然当额外类型的定义直接位于其使用站点之上时,这并不是那么糟糕。)
  • @Yakk 我明白了,我错误地将它与使用 decltype 的初始方法进行了比较。
  • 我认为索引的类型应该与范围的类型相同,因此这里的第二个选项“正确”。
【解决方案2】:

我假设您希望您的参数都是相同的类型,可能使用整数类型(我将使用int)。一种简单的方法是利用您已有的参数包:

template <int>
struct shape_helper { typedef int type; };

template <typename T, int... Shape>
class Array
{
public:
    T& operator()(typename shape_helper<Shape>::type...);
}; 

【讨论】:

  • 不知何故,我不想引入其他类型。喜欢在这里评论:stackoverflow.com/questions/26766617/…
  • @0x499602D2:是的,类型是故意的。
  • @Deduplicator:是的,使用decltype(shape, X())... 是一个巧妙的技巧。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-10-01
  • 1970-01-01
  • 2012-08-14
  • 2017-08-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多