Non-type variadic function templates in C++11

前端 未结 5 1443
有刺的猬
有刺的猬 2020-12-05 23:48

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

template 
stru         


        
相关标签:
5条回答
  • 2020-12-06 00:15

    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.

    0 讨论(0)
  • 2020-12-06 00:18

    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.

    0 讨论(0)
  • 2020-12-06 00:22

    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;
    }
    
    0 讨论(0)
  • 2020-12-06 00:23

    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.

    0 讨论(0)
  • 2020-12-06 00:34

    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.

    0 讨论(0)
提交回复
热议问题