2016-06-20 9 views
8

Chociaż powiedzmy std::add_pointer to jednoskładnikowa, następujący kod jest akceptowana zarówno przez GCC 7.0.0 (20160608) i Clang 3.9.0:Konkatenowanie kaczki parametr szablonu dla jednoargumentowego argumentu

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

Jednakże, podczas gdy następujący kod jest akceptowany przez Clang, jest odrzucany przez GCC:

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

Czy to jest prawidłowe C++? Syntaktycznie mogę sobie wyobrazić, że przecinek jest problemem, gdy paczki są puste, ale przypuszczalnie jest to usuwane przy innych okazjach; na przykład std::common_type akceptuje zero lub więcej argumentów, a następujące prezenty żaden problem dla obu kompilatora:

template <typename ...Ts> 
struct tc3 { 
    template <typename ...Us> 
    using c = std::common_type<Ts...,Us...>; 
}; 
+1

Uwaga: clang odrzuca tworzenie wystąpień, takich jak 'tc2 :: b <>', ale akceptuj 'tc2 <> :: b '. – Holt

+0

czy to ma sens? co specjalizuje się w długości dowolnego opisu wariantowego? Nie widzę niczego, co by to określiło, więc może być specyficzna dla implementacji, ale myślę, że mogłoby to być niezdefiniowane zachowanie – kirinthos

+3

["Program jest źle sformułowany, nie wymaga diagnostyki, jeśli: \ [... \] każda ważna specjalizacja szablonu variadic wymaga pustego pakietu parametrów szablonu "] (http://eel.is/c++draft/temp.res#8). –

Odpowiedz

1

Można użyć tego kodu dla dowolnej liczby argumentów szablonu tc3<1 or more>::a<zero or more> na GCC i 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; 
} 

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

Ten Poniższy kod jest akceptowany przez Clang tylko przed instantinationed, ale po tam jest błąd:

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

std::add_pointer<> może wziąć tylko jeden tamplte argument: http://en.cppreference.com/w/cpp/types/add_pointer

template< class T > 
struct add_pointer; 

Więcej niż jeden argument może zająć tylko w wewnętrznym namespace szczegółowo lub w jakiś inny:

ewentualnego wdrożenia:

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> {}; 

ten służy do obsługi tego kodu:

typedef std::add_pointer<bool(int, int)>::type ptr4; // bool(*)(int,int) 
Powiązane problemy