2017-02-09 16 views
2

Рассмотрим простой шаблон специализации:Частичная специализация шаблона с параметрами нетиповых: GCC против МСВС

template<typename T, size_t I> 
struct S {}; 

template<typename T> 
struct S<T, std::tuple_size<T>::value> {}; 

GCC не компилирует его, так как он использует параметр шаблона T в шаблоне аргумента std::tuple_size<T>::value:

error: template argument 'std::tuple_size<_Tp>::value' involves template parameter(s)

Теперь давайте заменим T с typename std::remove_reference<T>::type в tuple_size аргумент шаблона:

// Using primary structure template from previous example. 
template<typename T> 
struct S<T, std::tuple_size<typename std::remove_reference<T>::type>::value> {}; 

Этот код по-прежнему использует параметр шаблона в аргументе шаблона, но GCC компилирует его без каких-либо ошибок или предупреждений. Зачем?

Теперь, если мы попытаемся собрать второй пример использования МСВС с /std:c++latest флагом, он останавливается с ошибкой C2755:

non-type parameter of a partial specialization must be a simple identifier

Что это странное ограничение? Я хочу прекратить рекурсию времени компиляции, когда I станет равным размеру кортежа.

Так кто же из них не прав: MSVS или GCC?

Обратите внимание, что МСВС сообщает об ошибке, даже без какой-либо конкретизации шаблона, в то время как GCC работает отлично со всеми этими экземплярами:

S<std::tuple<int, float>, 9> s1; 
S<std::tuple<int, float>, 2> s2; 
S<int, 42> s3; 

Я использую МСВС Community 2015 Update 3 с его компилятор по умолчанию и GCC 6.2.1.

Tried Clang 3.8.0. Он не компилируется как фрагментов с ошибкой, подобными сообщениями GCC в:

error: non-type template argument depends on a template parameter of the partial specialization

ответ

3

Конкретный раздел стандарта, касающегося жизнеспособности частичного шаблона класса специализации изменилось много раз за последние несколько лет. Оригинальный restrictionin [temp.class.spec.match] читать:

A partially specialized non-type argument expression shall not involve a template parameter of the partial specialization except when the argument expression is a simple identifier.

Ваш код явно идет вразрез что, std::tuple_size<T>::value не является идентификатором.

Затем он изменил, после cwg issue 1315 следующего содержания:

Each template-parameter shall appear at least once in the template-id outside a non-deduced context.

Но мы хорошо там - T используется в не выводится контексте в качестве первого параметра шаблона. И после того, как template auto, теперь гласит:

If the template arguments of a partial specialization cannot be deduced because of the structure of its template-parameter-list and the template-id, the program is ill-formed.

Но мы хорошо там. Это можно сделать, у вас есть правильная «структура» - ваша специализация использует параметр шаблона непигового типа в том же месте, что и основной, и они должны соответствовать штрафу.


Я думаю, после разрешения 1315 (который я считаю пост -C++, 14), код должен быть хорошо образован, но оба GCC и лязг отклонить его.Неудачный исправление будет использовать два Типу параметры вместо:

template <class T, class I> 
struct S; 

template<typename T> 
struct S<T, typename std::tuple_size<T>::type> {}; 

template <size_t I> 
using size_ = std::integral_constant<size_t, I>; 

int main() { 
    S<std::tuple<int>, size_<1>> s; 
} 

Оба НКУ и лязг принять, что один.