В стандарте C ++ в параграфе 2 [temp.class.spec.match] говорится:
Частичная специализация соответствует заданному фактическому списку аргументов шаблона, если аргументы шаблона частичной специализации могут быть выведены из фактического списка аргументов шаблона (14.8.2).
14.8.2 - это [temp.arg.deduct], т.е. предложение, описывающее вывод аргументов шаблона для шаблонов функций.
Если вы измените свой код для использования аналогичного шаблона функции и попытаетесь вызвать его, вы увидите, что аргументы не могут быть выведены:
template <typename String, typename T>
void deduction_test(String,
typename basic_data_object<String, std::allocator>::template array_container<T>)
{ }
int main()
{
deduction_test(std::string{}, std::vector<int, std::allocator<int>>{});
}
(Я удалил параметр Allocator
, поскольку нет возможности передать параметр шаблона шаблона в качестве аргумента функции, а в типе basic_data_object
это невыведенный контекст, я не верю, что это влияет на результат.)
И clang, и GCC говорят, что не могут вывести здесь T
. Следовательно, частичная специализация не будет соответствовать тем же типам, которые используются в качестве аргументов шаблона.
Так что я еще не ответил на этот вопрос, только пояснил, что причина кроется в правилах вывода аргументов шаблона, и показал эквивалентность вывода в шаблонах функций.
В 14.8.2.5 [temp.deduct.type] мы получаем список невыведенных контекстов, которые предотвращают дедукцию, и следующее правило в параграфе 6:
Когда имя типа указывается способом, который включает невыведенный контекст, все типы, составляющие это имя типа, также не выводятся.
Поскольку basic_data_object<String, Allocator>
находится в невыведенном контексте (это спецификатор вложенного-имени, т.е. появляется перед ::
), это означает, что тип T
также не выводится, что именно об этом говорят Clang и GCC. нас.
С вашим временным жестко запрограммированным typedef нет невыведенного контекста, поэтому вывод для T
выполняется успешно с использованием шаблона функции deduction_test
:
template <typename String, typename T>
void deduction_test(String,
typename data_object::template array_container<T>)
{ }
int main()
{
deduction_test(std::string{}, std::vector<int, std::allocator<int>>{}); // OK
}
И, соответственно, частичная специализация вашего шаблона класса может быть сопоставлена, когда он использует этот тип.
Я не вижу способа заставить его работать без изменения определения get_data_object_value
, но если это вариант, вы можете избавиться от необходимости выводить тип array_container
и вместо этого использовать черту, чтобы определить, является ли тип тем типом, который вы хотите, и специализируемся на результате признака:
#include <string>
#include <vector>
#include <iostream>
template <typename String, template<class> class Allocator>
class basic_data_object
{
public:
template<typename T>
using array_container = std::vector<T, Allocator<T>>;
template<typename T>
struct is_ac : std::false_type { };
template<typename T>
struct is_ac<array_container<T>> : std::true_type { };
};
template <typename String, template<class> class Allocator, typename T, bool = basic_data_object<String, Allocator>::template is_ac<T>::value>
struct get_data_object_value
{
};
template <typename String, template<class> class Allocator, typename T>
struct get_data_object_value<String, Allocator, T, true>
{
void f() { }
};
int main()
{
get_data_object_value<std::string,std::allocator,std::vector<short>> obj;
obj.f();
}
На самом деле это не масштабируется, если вам нужно несколько частичных специализаций шаблона класса, поскольку вам нужно будет добавить несколько bool
параметров шаблона с аргументами по умолчанию.
person
Jonathan Wakely
schedule
02.05.2014
typename
, но, похоже, здесь дело обстоит не так. - person Bathsheba   schedule 29.04.2014String
иAllocator
из последнего аргумента. - person dyp   schedule 29.04.2014is_instantiation_of
не работает должным образом. - person dyp   schedule 30.04.2014template <class> class Allocator
отовсюду, но это все равно не удалось; таким образом,Allocator
не является частью проблемы. - person Matthieu M.   schedule 02.05.2014