具有由整数

时间:2017-12-18 10:37:08

标签: c++ function c++11 c++14 c++17

我有一个带有接受整数的模板的类:

template <unsigned int N>
class Example {};

我正在寻找一种方法来定义一个(成员)函数,该函数接受一些Example个对象作为参数。金额由N确定,因此函数将使用如下:

Function(Example<2>(), Example<2>());
Function(Example<3>(), Example<3>(), Example<3>());

到目前为止我尝试了什么:

使用初始化列表,可以将一组对象传递给函数:

template <unsigned int N>
void Function(std::initializer_list<Example<N>> list);
//...
Function({Example<2>(), Example<2>()});

然而,除了真正只传递一个参数(列表)之外的问题是,使用此方法可以使用任意数量的参数:

Function({Example<2>()});

我也尝试过使用可变参数函数:

template <unsigned int N>
void Function(Example<N> e...)
{
    va_list args;
    va_start(args, e);
    //...
}
Function(Example<2>(), Example<2>());

这使得可以使用真实参数,但仍然存在使用任意数量参数的问题,并且不可能知道实际传递了多少参数。

5 个答案:

答案 0 :(得分:21)

假设您希望从Example<N>类型中推断出参数的数量,并且所有Example<I>应该共享相同的N,那么C ++ 17解决方案可能< / p>

template <unsigned int... I>
auto Function( Example<I>... ) ->
    std::enable_if_t<( ( I == sizeof...(I) ) && ... )>
{
   // or static_assert() if you always want an error
}

答案 1 :(得分:5)

使Function成为可变参数模板并使用std::enable_if_t约束它:

  • 可以使用某些IsExample特征来确保所有参数都是Example的实例

  • sizeof...(pack)可用于获取参数包的大小

template <unsigned int N, typename... Ts>
auto Function(Ts... xs) 
    -> std::enable_if_t<(IsExample<Ts>::value && ...) 
                     && (sizeof...(Ts) == N)>
{
}

live example on wandbox

答案 2 :(得分:5)

您应该使用variadic函数模板和static_assert。与涉及enable_if的方法不同,如果传递的参数不正确,则会产生可读错误消息。

template<unsigned int ... I>
void Function(Example<I>... items)
{
    static_assert
    (
        true && (... && (static_cast<unsigned int>(sizeof...(I)) == I))
    ,   "This function accepts N arguments of type Example<N>"
    );
}

Online compiler

答案 3 :(得分:2)

有许多答案涵盖SFINAE友好的约束,但我不喜欢将我的SFINAE放在返回值中:

template <unsigned int... Is,
  std::enable_if_t<( ( Is == sizeof...(Is) ) && ... ), bool> = true
>
void Function( Example<Is>... examples )
{
  // code
}

template<bool b>
using test_requirement = std::enable_if_t<b, bool>;

template <unsigned int... Is,
  test_requirement<( ( Is == sizeof...(Is) ) && ... )> = true
>
void Function( Example<Is>... examples )
{
  // code
}

答案 4 :(得分:0)

+1为Massimiliano Janes的优雅解决方案。

不幸的是,使用折叠只适用于C ++ 17。

使用C ++ 11 / C ++ 14测试所有I等于sizeof...(I)(并且sizeof...(I)可能等于N,其中N是类模板参数),它足以测试接收无符号值的可变类型是具有不同值顺序的相同类型。

我的意思是:将一个简单的结构声明为

template <std::size_t ... Is>
struct IList;

测试可以

std::is_same<IList<N, sizeof...(Is), Is...>,
             IList<sizeof...(Is), Is..., N>>::value

从C ++ 14开始,可以使用std::index_sequence代替IList

所以Example可以写成

template <unsigned int N>
struct Example
 {
   template <unsigned int ... Is>
   auto Function (Example<Is> ...)
      -> typename std::enable_if<
            std::is_same<IList<N, sizeof...(Is), Is...>,
                         IList<sizeof...(Is), Is..., N>>::value>::type
    { /* do something */ }
 };

以下是使用示例(但请记住包含<type_traits>

int main()
 {
   Example<1U> e1;
   Example<2U> e2;

   // e1.Function(); // error
   e1.Function(Example<1>{}); // compile
   //e1.Function(Example<1>{}, Example<1>{}); // error

   // e2.Function(); // error
   //e2.Function(Example<2>{}); // error
   e2.Function(Example<2>{}, Example<2>{}); // compile
   //e2.Function(Example<2>{}, Example<2>{}, Example<2>{}); // error
 }