Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Concatenating template parameter packs for a unary argument

Although, say, std::add_pointer is unary, the following code is accepted by both GCC 7.0.0 (20160608) and Clang 3.9.0:

template <typename ...Ts>
struct tc1 {
  using a = std::add_pointer<Ts...>;
};

However, while the following code is accepted by Clang, it is rejected by GCC:

template <typename ...Ts>
struct tc2 {
  template <typename ...Us>
  using b = std::add_pointer<Ts...,Us...>;
};

Is this valid C++? Syntactically, I could imagine that the comma is a problem when packs are empty, but presumably it is elided on other occasions; for example, std::common_type accepts zero or more arguments, and the following presents no problem for either compiler:

template <typename ...Ts>
struct tc3 {
  template <typename ...Us>
  using c = std::common_type<Ts...,Us...>;
};
like image 801
user2023370 Avatar asked Jun 20 '16 13:06

user2023370


1 Answers

You can use this code for any number of template arguments tc3<1 or more>::a<zero or more>, on GCC and Clang:

#include <type_traits>

struct A {
    template<typename ...Args> A(Args ... args) {}
};

template <typename T, typename ...Ts>
struct tc3 {
  template <typename ...Us>
  using c = std::add_pointer<T(Ts...,Us...)>;
};

int main() {
    typedef tc3<A, int, float>::template c<unsigned, double>::type  ptr;// A(*)(int,float,unsigned,double)
    typedef tc3<A>::template c<>::type ptr2;                // A(*)()
    typedef tc3<bool>::template c<int, int>::type ptr3;     // bool(*)(int,int)
    typedef std::add_pointer<bool(int, int)>::type ptr4;    // bool(*)(int,int)

    return 0;
}
  • GCC 7.0.0: http://melpon.org/wandbox/permlink/m7Re0kFevMjalv6s
  • Clang 4.0.0: http://melpon.org/wandbox/permlink/mXDtQRN7COxhtLN8

However, while the following code is accepted by Clang, it is rejected by GCC:

This following code is accepted by Clang only before instantinationed, but after there is error:

template <typename ...Ts>
struct tc2 {
  template <typename ...Us>
  using b = std::add_pointer<Ts...,Us...>;
};
  • error Clang 4.0: http://melpon.org/wandbox/permlink/vpBCJHlvWk1ai1ny
  • error GCC 7.0.0: http://melpon.org/wandbox/permlink/a1rRfDI5zcUz3nau

std::add_pointer<> can take only one tamplte argument: http://en.cppreference.com/w/cpp/types/add_pointer

template< class T >
struct add_pointer;

More than one argument it can take only in internal namespace detail or in some else:

Possible implementation:

namespace detail {
    template< class T, bool is_function_type = false >
    struct add_pointer {
        using type = typename std::remove_reference<T>::type*;
    };

    template< class T >
    struct add_pointer<T, true> {
        using type = T;
    };

    template< class T, class... Args >
    struct add_pointer<T(Args...), true> {
        using type = T(*)(Args...);
    };

    template< class T, class... Args >
    struct add_pointer<T(Args..., ...), true> {
        using type = T(*)(Args..., ...);
    };

} // namespace detail

template< class T >
struct add_pointer : detail::add_pointer<T, std::is_function<T>::value> {};

This is done to support this code:

typedef std::add_pointer<bool(int, int)>::type ptr4;    // bool(*)(int,int)
like image 54
Alex Avatar answered Nov 06 '22 10:11

Alex