变异函数

时间:2017-12-16 20:46:24

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

我正在尝试编写一个表示张量Tensor的类,并希望为2维张量提供语法tensor(i, j),为3维张量提供tensor (i, j, k)等等

我想知道的是,是否有一种c ++类型的安全方式来声明这样的Tensor:operator()(int, int, ...)接受任意数量的int个参数(除了C样式和宏va_start va_end)以及如何在函数内使用所述参数。

感谢您的时间。

4 个答案:

答案 0 :(得分:2)

好吧,你总是可以使用普通的参数包;但强制编译失败,除非所有参数都是int s:

#include <utility>
#include <type_traits>


class foo {

public:

    template<typename ...Args,
         typename=std::void_t<std::enable_if_t
                      <std::is_same_v<Args, int>>...>>
    void operator()(Args ...args)
    {
    }
};

void bar()
{
    foo bar;

    bar(4, 2);
}

那将编译,但不是:

bar(4, "foo");

bar(4, 2.3);

请注意,这不会编译:

unsigned baz=2;

bar(4, baz);

如果您需要接受无符号值,请相应地调整模板。

请注意,模板不需要使用转发引用,因为唯一可接受的参数是普通int s。在模板功能中,您现在拥有一个多种多样的参数包,您可以使用与使用任何其他参数包相同的方式。

答案 1 :(得分:1)

同时接受unsigned int和其他可转换为int的类型,如果你可以接受上限(63,在下面的例子中)到整数参数的数量,我建议关注an example from W.F.

所以你可以开发一个typer

template <typename T, std::size_t>
using typer = T;

和递归struct proOp

template <typename T, std::size_t N = 64U,
          typename = std::make_index_sequence<N>>
struct proOp;

template <typename T, std::size_t N, std::size_t... Is>
struct proOp<T, N, std::index_sequence<Is...>> : public proOp<T, N-1U>
 {
   using proOp<T, N-1U>::operator();

   void operator() (typer<T, Is>... ts)
    { }
 };

template <typename T>
struct proOp<T, 0U, std::index_sequence<>>
 {
   void operator() ()
    { }
 };

继承proOp<int>Tensor成为

struct Tensor : public proOp<int>
 {
   using proOp<int>::operator();
 };

以下是一个完整的工作示例

#include <utility>

template <typename T, std::size_t>
using typer = T;

template <typename T, std::size_t N = 64U,
          typename = std::make_index_sequence<N>>
struct proOp;

template <typename T, std::size_t N, std::size_t... Is>
struct proOp<T, N, std::index_sequence<Is...>> : public proOp<T, N-1U>
 {
   using proOp<T, N-1U>::operator();

   void operator() (typer<T, Is>... ts)
    { }
 };

template <typename T>
struct proOp<T, 0U, std::index_sequence<>>
 {
   void operator() ()
    { }
 };

struct Tensor : public proOp<int>
 {
   using proOp<int>::operator();
 };

int main()
 {
   Tensor t;

   t(1, 2, 3);
   t(1, 2, 3, 4U); // accept also unsigned
   //t(1, "two"); // error
 }

答案 2 :(得分:1)

另一种方法是使operator()递归并在每次递归中使用第一个参数

   // recursive case
   template <typename ... Ts>
   void operator() (int i0, Ts ... is)
    {
      // do something with i0
      this->operator()(is...); // recursion
    }

   void operator() ()
    { }

以下是一个完整的工作示例

struct Tensor
 {
   // recursive case
   template <typename ... Ts>
   void operator() (int i0, Ts ... is)
    {
      // do something with i0
      this->operator()(is...); // recursion
    }

   void operator() ()
    { }
 };

int main()
 {
   Tensor t;

   t(1, 2, 3);
   t(1, 2, 3, 4U); // accept also unsigned
   //t(1, "two"); // error
 }

答案 3 :(得分:0)

有一种更简洁的方法来创建安全的可变参数函数,而不使用递归和std :: enable_if:

template <typename ...Ints>
void function(int first, Ints... other)
{
    int values[] = {first, other...};
    for(int value : values)
    {
        //your code
    }
}

这种方式也是类型安全的,function(1, "2", 3)无法编译。