C++ 为什么可以';是否无法为此嵌套模板结构推断此函数的模板参数?
我有一个嵌套的模板结构:C++ 为什么可以';是否无法为此嵌套模板结构推断此函数的模板参数?,c++,templates,C++,Templates,我有一个嵌套的模板结构: template <typename... Ts> struct A { template <unsigned i> struct B { int b; }; }; 为什么呢?如何使其不必在函数调用中指定模板参数 请尝试以下代码:模板参数推断无法推断嵌套名称说明符中出现的任何内容。例如,它不允许从类型为typename Foo::bar的参数推断t。我相信原因是一般来说是不可能扣减的,;总有一些Foo的局部专门化将bar
template <typename... Ts>
struct A
{
template <unsigned i>
struct B
{
int b;
};
};
为什么呢?如何使其不必在函数调用中指定模板参数
请尝试以下代码:模板参数推断无法推断嵌套名称说明符中出现的任何内容。例如,它不允许从类型为
typename Foo::bar
的参数推断t
。我相信原因是一般来说是不可能扣减的,;总有一些Foo
的局部专门化将bar
定义为任意复杂的typedef
解决方法是将嵌套类型定义为未列出的类型,然后使用typedef
将其引入,但使用原始未列出的名称进行推断:
template <unsigned i, typename... Ts>
struct A_B { int b; }
template <typename... Ts>
struct A {
template <unsigned i> using B = A_B<i, Ts...>;
};
template <unsigned i, typename... Ts>
void foo(A_B<i, Ts...> var);
模板
结构A_B{int B;}
样板
结构A{
使用B=A_B的模板;
};
样板
无效foo(A_B var);
因为标准上这么说
该标准之所以这么说,是因为反转任意编译时映射相当于暂停
这相当于暂停,因为模板元编程是图灵完成的
它是图灵完备的,因为实际上很难制作出一种有用的编程语言,而这种语言不是图灵完备的;它是偶然发生的,避免它会导致语言对于看似简单的事情需要烦人的变通方法
一般来说,确定哪一个<代码> A<代码> <代码>:::B/<代码>是来自和反转映射,所以很难,所以C++标准称编译器不尝试。< /P>
如果您编写自己的映射,您就可以这样做。首先,您必须认识到
B
类型没有“头发”,因为B
类型没有将其附加回用于创建它的A
类型。我们可以添加“头发”:
从中我们可以从B
获得A
的模板参数:
template<class...Ts, unsigned i>
void foo( types_t<Ts...>, std::integral_constant<unsigned, i>, typename A<Ts...>::template B<i> var ) {
}
template<class B>
void foo( B b ) {
using types = get_types_t< typename B::daddy >;
using index = get_B_index< B >;
return foo( types{}, index{}, b );
}
模板
void foo(types\u t,std::integral\u常量,typename A::template B var){
}
样板
无效foo(B){
使用类型=获取类型;
使用索引=获取索引;
返回foo(类型{},索引{},b);
}
在您的特定情况下,嵌套类型
B
唯一地附加到封闭类型A
的特定专门化。各种B
s和它们所包含的A
s之间有一对一的对应关系。因此,理论上可以从特定的B
推导出A
的参数
但是,在一般情况下,嵌套类型名可能引用别名(例如typedef name),而不是真正的新类型名(如您的示例中)。对于嵌套别名,1:1对应关系不再成立,其他答案中的示例说明了这一点
语言规范没有区分这两种情况(真正新的嵌套类型与嵌套别名),因此它选择“公分母”方法,只是始终将封闭的模板参数视为非推导上下文。在这种竞争中推导类型是不合理的。首先,它不一定是一对一的映射。谢谢,我喜欢这个解决方案,因为你的答案很简单。我没想到事情会变得这么复杂。当你说它等同于停止时,你指的是停止问题吗?“B的类型与创建它所用的A的类型没有关系。”好吧,一般情况下,这句话是不正确的。定义新的嵌套类型(如本例中的嵌套类定义)时,嵌套类型将唯一且明确地附加到封闭类型。“无附件”情况仅在嵌套类型为别名(例如typedef名称)时出现。语言规范根本不想区分这两种情况,而是选择“最低公分母”。@tuket是的,我是。它被称为HALT。Ant更明确,在C++代码中,没有从A类型到它定义的类型的方法。它在其中定义的名称空间可以通过在每个名称空间中注入一个具有唯一名称的helper函数进行测试,然后进行仔细的ADL来实现。可以添加一种方法来实现这一点,但它并不存在。
A<int, float>::B<0> var = {0};
foo(var);
A<int, float>::B<0> var = {0};
foo<0, int, float>(var);
template <unsigned i, typename... Ts>
struct A_B { int b; }
template <typename... Ts>
struct A {
template <unsigned i> using B = A_B<i, Ts...>;
};
template <unsigned i, typename... Ts>
void foo(A_B<i, Ts...> var);
template<class...Ts>
struct A {
template<unsigned i>
struct B {
using daddy = A;
int b;
};
};
template<class...Ts>
struct types_t {using type=types_t;};
template<class X>
struct get_types;
template<class X>
using get_types_t=typename get_types<X>::type;
template<template<class...>class Z, class...Ts>
struct get_types<Z<Ts...>>:types_t<Ts...>{};
template<class B>
struct get_B_index;
template<unsigned i, template<unsigned>class B>
struct get_B_index<B<i>>:std::integral_constant<unsigned, i>{};
template<class...Ts, unsigned i>
void foo( types_t<Ts...>, std::integral_constant<unsigned, i>, typename A<Ts...>::template B<i> var ) {
}
template<class B>
void foo( B b ) {
using types = get_types_t< typename B::daddy >;
using index = get_B_index< B >;
return foo( types{}, index{}, b );
}