2016-06-20 102 views
8

雖然說,std::add_pointer是一元的,下面的代碼是由兩個GCC 7.0.0(20160608)和3.9.0鏘接受:拼接模板參數包爲一元的說法

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

然而,當以下代碼被Clang接受,它被GCC拒絕:

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

這是有效的C++嗎?在句法上,我可以想象,當包裝是空的時,逗號是個問題,但大概是在其他場合消除了;例如,std::common_type接受零個或多個參數,下面介紹的兩種編譯器沒有問題:

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

注:clang拒絕實例化,例如'tc2 :: b <>'但接受'tc2 <> :: b '。 – Holt

+0

這有意義嗎?什麼是專門的可變參數描述的長度?我沒有看到任何可以確定的東西,所以可能是特定於實現的,但我認爲可能是未定義的行爲 – kirinthos

+3

[「程序不合格,不需要診斷,如果:\ [... \]每個有效的專業化的可變模板需要一個空的模板參數包「](http://eel.is/c++draft/temp.res#8)。 –

回答

1

您可以使用此代碼的任何數量的模板參數tc3<1 or more>::a<zero or more>,對GCC和鏘:

#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:

這下面的代碼是由鏘只接受前instantinationed,但畢竟有錯誤:

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

std::add_pointer<>只能取一個tamplte參數:http://en.cppreference.com/w/cpp/types/add_pointer

template< class T > 
struct add_pointer; 

不是一個參數更可以採取只在內部namespace細節或某些其他:

可能的實現:

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

這完成以支持此代碼:

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