这可能只是语法问题。
所以我有这个模板类:
template <typename String, template<class> class Allocator>
class basic_data_object
{
template<typename T>
using array_container = std::vector<T, Allocator<T>>;
};
还有一个:
template <typename String, template<class> class Allocator, typename T>
struct get_data_object_value
{
};
现在我想用第一个的内部 typedef array_container
为任何给定类型专门化第二个的 T
参数。
template <typename String, template<class> class Allocator, typename T>
struct get_data_object_value
<String, Allocator,
typename basic_data_object<String, Allocator>::template array_container<T>>
{
};
但是当我将 std::vector 作为最后一个参数传递时,这种特化似乎不匹配。
如果我创建一个临时硬编码 typedef:
typedef basic_data_object<std::string, std::allocator<std::string>> data_object;
并将其用于特化,一切正常:
template <typename String, template<class> class Allocator, typename T>
struct get_data_object_value
<String, Allocator,
data_object::template array_container<T>>
{
};
我错过了什么? :)
或者,使这项工作的最佳(最小/最干净)方法是什么?
最佳答案
C++ 标准在 [temp.class.spec.match] 第 2 段中说:
A partial specialization matches a given actual template argument list if the template arguments of the partial specialization can be deduced from the actual template argument list (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 段中的以下规则:
When a type name is specified in a way that includes a non-deduced context, all of the types that comprise that type name are also non-deduced.
自从 basic_data_object<String, Allocator>
在非推导上下文中(它是一个 nested-name-specifier,即出现在 ::
之前),表示类型 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
的需要type 而是使用一个 trait 来检测一个类型是否是你想要的类型,并专注于 trait 的结果:
#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
带有默认参数的模板参数。
关于c++ - 模板类模板成员的模板特化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23362391/