C++11 中的非类型可变参数函数模板

发布于 2024-12-11 18:05:24 字数 717 浏览 0 评论 0原文

我看到一篇博客文章,其中使用了非type 可变参数模板(目前 gcc 不支持,仅 clang 支持)。

template <class T, size_t... Dimensions>
struct MultiDimArray { /* ... */ };

帖子中的示例编译得很好,但我无法让它与函数模板一起使用。

任何人都可以帮助找出正确的语法(如果存在)吗?

int max(int n) { return n; } // end condition

template <int... N> // replacing int... with typename... works
int max(int n, N... rest) // !! error: unknown type name 'N'
{
    int tmp = max(rest...);
    return n < tmp? tmp : n;
}

#include <iostream>
int main() 
{
   std::cout << max(3, 1, 4, 2, 5, 0) << std::endl;   
}

I saw a blog post which used non-type variadic templates (currently not supported by gcc, only by clang).

template <class T, size_t... Dimensions>
struct MultiDimArray { /* ... */ };

The example in the post compiles fine but I failed to get it to work with function templates.

Can anyone help figuring out the correct syntax (if such exists)?

int max(int n) { return n; } // end condition

template <int... N> // replacing int... with typename... works
int max(int n, N... rest) // !! error: unknown type name 'N'
{
    int tmp = max(rest...);
    return n < tmp? tmp : n;
}

#include <iostream>
int main() 
{
   std::cout << max(3, 1, 4, 2, 5, 0) << std::endl;   
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

等待圉鍢 2024-12-18 18:05:24

这将打印出所有元素,
get max 可以类似地实现

template <int N>
void foo(){
  cout << N << endl;
}

template <int N, int M, int ... Rest>
void foo(){
  cout << N << endl;
  foo<M, Rest...>();
}


int main(){
  foo<1, 5, 7>();

  return 0;
}

This will print out all elements,
get max could be implemented similarly

template <int N>
void foo(){
  cout << N << endl;
}

template <int N, int M, int ... Rest>
void foo(){
  cout << N << endl;
  foo<M, Rest...>();
}


int main(){
  foo<1, 5, 7>();

  return 0;
}
孤千羽 2024-12-18 18:05:24

您只是混淆了类型名称和非类型名称。你想要的根本行不通。

可以在函数中使用可变参数非类型模板,但不能作为(非模板)参数:

template <int N, int... Rest>
int max()
{
    int tmp = max<Rest...>();
    return N < tmp ? tmp : N;
}
std::cout << max<3, 1, 4, 2, 5, 0>() << std::endl;

...虽然我还没有测试过这一点,并且我不确定如何 鉴于您需要部分专业化作为基本情况,这应该可行。您可以通过分派到部分专用的结构来解决此问题:

template <int N, int... Rest>
struct max_t {
    static int const value = max_t<Rest...>::value > N ? max_t<Rest...>::value : N;
};

template <int N>
struct max_t<N> {
    static int const value = N;
};


template <int... NS>
int max()
{
    return max_t<NS...>::value;
}

这会起作用。

You are simply confusing type names and non-type names. What you want simply doesn’t work.

You can probably use variadic non-type templates in functions, but not as (non-template) arguments:

template <int N, int... Rest>
int max()
{
    int tmp = max<Rest...>();
    return N < tmp ? tmp : N;
}
std::cout << max<3, 1, 4, 2, 5, 0>() << std::endl;

… although I haven’t tested this and I’m not sure how this should work given that you need to have a partial specialisation as the base case. You could solve this by dispatching to a partially specialised struct:

template <int N, int... Rest>
struct max_t {
    static int const value = max_t<Rest...>::value > N ? max_t<Rest...>::value : N;
};

template <int N>
struct max_t<N> {
    static int const value = N;
};


template <int... NS>
int max()
{
    return max_t<NS...>::value;
}

This will work.

断桥再见 2024-12-18 18:05:24

以下是定义仅接受 int 参数的可变参数函数模板的两种方法。第一个在实例化时生成硬错误,第二个使用 SFINAE:

template<typename... T>
struct and_: std::true_type {};

template<typename First, typename... Rest>
struct and_
: std::integral_constant<
    bool
    , First::value && and_<Rest...>::value
> {};

template<typename... T>
void
foo(T... t)
{
    static_assert(
        and_<std::is_same<T, int>...>::value
        , "Invalid parameter was passed" );
    // ...
}

template<
    typename... T
    , typename = typename std::enable_if<
        and_<std::is_same<T, int>...>::value
    >::type
>
void
foo(T... t)
{
    // ...
}

如您所见,此处不使用非类型模板参数。

Here are two ways of defining a variadic function template only accepting int parameters. The first one generates a hard-error when instantiated, the second uses SFINAE:

template<typename... T>
struct and_: std::true_type {};

template<typename First, typename... Rest>
struct and_
: std::integral_constant<
    bool
    , First::value && and_<Rest...>::value
> {};

template<typename... T>
void
foo(T... t)
{
    static_assert(
        and_<std::is_same<T, int>...>::value
        , "Invalid parameter was passed" );
    // ...
}

template<
    typename... T
    , typename = typename std::enable_if<
        and_<std::is_same<T, int>...>::value
    >::type
>
void
foo(T... t)
{
    // ...
}

As you can see, non-type template parameters aren't used here.

银河中√捞星星 2024-12-18 18:05:24

Luc Danton 的解决方案对于非 int 类型但可以隐式转换为 int 的参数无法正确运行。下面是这样做的:

template<typename T, typename U> struct first_type { typedef T type; };
template<typename T> int max_checked(T n) { return n; }
template<typename T1, typename T2, typename ...Ts>
int max_checked(T1 n1, T2 n2, Ts ...ns)
{
  int maxRest = max_checked(n2, ns...);
  return n1 > maxRest ? n1 : maxRest;
}
template<typename ...T> auto max(T &&...t) ->
  decltype(max_checked<typename first_type<int, T>::type...>(t...))
{
  return max_checked<typename first_type<int, T>::type...>(t...);
}

struct S { operator int() { return 3; } };
int v = max(1, 2.0, S()); // v = 3.

这里,max 将所有参数原封不动地转发给 max_checked,它采用相同数量的 int 类型的参数(通过执行first_type 模板上的包扩展)。如果任何参数无法转换为 int,则使用 decltype(...) 返回类型来应用 SFINAE。

Luc Danton's solution doesn't behave correctly with parameters which are not of type int, but can be implicitly converted to an int. Here's one which does:

template<typename T, typename U> struct first_type { typedef T type; };
template<typename T> int max_checked(T n) { return n; }
template<typename T1, typename T2, typename ...Ts>
int max_checked(T1 n1, T2 n2, Ts ...ns)
{
  int maxRest = max_checked(n2, ns...);
  return n1 > maxRest ? n1 : maxRest;
}
template<typename ...T> auto max(T &&...t) ->
  decltype(max_checked<typename first_type<int, T>::type...>(t...))
{
  return max_checked<typename first_type<int, T>::type...>(t...);
}

struct S { operator int() { return 3; } };
int v = max(1, 2.0, S()); // v = 3.

Here, max forwards all arguments unchanged to max_checked, which takes the same number of arguments of type int (provided by performing a pack-expansion on the first_type template). The decltype(...) return type is used to apply SFINAE if any argument can't be converted to int.

余厌 2024-12-18 18:05:24

以下是如何在 max 示例中实现可变参数,以便它可以采用任意数量的算术参数:

template<typename T, typename ... Ts>
struct are_arithmetic{
    enum {
        value = std::is_arithmetic<T>::value && are_arithmetic<Ts...>::value
    };
};

template<typename T>
struct are_arithmetic<T>{
    enum {
        value = std::is_arithmetic<T>::value
    };
};

template<typename Arg, typename = typename std::enable_if<std::is_arithmetic<Arg>::value>::type>
Arg max(Arg arg){
    return arg;
}

template<typename Arg, typename Arg1, typename ... Args, typename = typename std::enable_if<are_arithmetic<Arg, Arg1, Args...>::value>::type>
auto max(Arg arg, Arg1 arg1, Args ... args){
    auto max_rest = max(arg1, args...);
    return arg > max_rest ? arg : max_rest;
}

int main(){
    auto res = max(1.0, 2, 3.0f, 5, 7l);
}

这很好,因为它可以采用任何数字类型,并且将按其原始类型返回最大数字,而不是不仅仅是int

Here's how you could achieve variadic args in your max example such that it can take any number of arithmetic arguments:

template<typename T, typename ... Ts>
struct are_arithmetic{
    enum {
        value = std::is_arithmetic<T>::value && are_arithmetic<Ts...>::value
    };
};

template<typename T>
struct are_arithmetic<T>{
    enum {
        value = std::is_arithmetic<T>::value
    };
};

template<typename Arg, typename = typename std::enable_if<std::is_arithmetic<Arg>::value>::type>
Arg max(Arg arg){
    return arg;
}

template<typename Arg, typename Arg1, typename ... Args, typename = typename std::enable_if<are_arithmetic<Arg, Arg1, Args...>::value>::type>
auto max(Arg arg, Arg1 arg1, Args ... args){
    auto max_rest = max(arg1, args...);
    return arg > max_rest ? arg : max_rest;
}

int main(){
    auto res = max(1.0, 2, 3.0f, 5, 7l);
}

This is good because it can take any numeric type and will return the maximum number by its original type rather than just int, too.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文