简体   繁体   English

为什么不能为此嵌套模板化结构推断此函数的模板参数?

[英]Why can't the template parameters of this function be inferred for this nested templated struct?

I have this nested templated struct: 我有这个嵌套的模板结构:

template <typename... Ts>
struct A
{
  template <unsigned i>
  struct B
  {
    int b;
  };
};

That compiles fine. 这样编译就可以了。

Then I try to define this function. 然后,我尝试定义此功能。

template <unsigned i, typename... Ts>
void foo(A<Ts...>::B<i> var)
{
  std::cout << var.b << std::endl;
}

For some reason I don't completely understand, that won't compile. 由于某种原因,我不完全了解,因此无法编译。 I had to change it in the following way for it to work. 我必须按照以下方式对其进行更改才能使其工作。

template <unsigned i, typename... Ts>
void foo(typename A<Ts...>::template B<i> var)
{
  std::cout << var.b << std::endl;
}

But then, when I call it like so: 但是,当我这样称呼它时:

A<int, float>::B<0> var = {0};
foo(var);

It says that template parameter i cannot be deducted. 它说模板参数i不能被扣除。

I can make it work by adding the template arguments explicitly to the function call: 我可以通过将模板参数显式添加到函数调用中来使其工作:

A<int, float>::B<0> var = {0};
foo<0, int, float>(var);

Why is that? 这是为什么? How can I make it so I don't have to specify the template parameters in the function call? 如何做到这一点,而不必在函数调用中指定模板参数?

Try the code: https://repl.it/repls/LavenderDefiantOctagons 尝试代码: https : //repl.it/repls/LavenderDefiantOctagons

Because the standard says so. 因为标准是这样说的。

The standard says so because inverting arbitrary compile time maps is equivalent to Halt. 该标准之所以这样说是因为反转任意编译时间图等效于Halt。

It is equivalent to Halt because template metaprogramming is Turing complete. 它等效于Halt,因为模板元编程已完成Turing。

It is Turing complete because it is actually hard to make a useful programming language that isn't Turing complete; 这是图灵完整的,因为实际上很难制作出不是图灵完整的有用的编程语言。 it happens by accident, and avoiding it leads to a language that requires annoying workaround for seemingly simple things. 它是偶然发生的,避免使用它会导致一种语言,它需要对看似简单的事物进行恼人的解决方法。

So the problem in general, of determining which A the A<int, float>::B<0> is from and reversing that mapping, is hard, so the C++ standard says the compiler doesn't try. 因此,通常很难确定A<int, float>::B<0>来自哪个A并反转该映射的问题,因此C ++标准表示编译器不尝试。

If you write your own mapping you can do it. 如果您编写自己的映射,则可以做到。 First, you have to realize that B types have no "hair" in that there is nothing about the type of B that attaches it back to the type of A used to create it. 首先,你必须认识到, B种没有“毛”中,有大约类型没什么B ,重视回的类型, A用于创建它。 We can add "hair": 我们可以添加“头发”:

template<class...Ts>
struct A {
  template<unsigned i>
  struct B {
    using daddy = A;
    int b;
  };
};

now we can find A from the type of B<?> . 现在我们可以从B<?>的类型中找到A

Next let's add some inverse maps: 接下来,让我们添加一些逆映射:

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

and from this we can get A 's template arguments from B : 然后我们可以从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 );
 }

Live example 现场例子

Template argument deduction can't deduce anything that appears in a nested-name-specifier . 模板自变量推导无法推断出嵌套名称说明符中出现的任何内容。 For example, it won't allow T to be deduced from a parameter of type typename Foo<T>::bar . 例如,它不会允许T从类型的参数来推断typename Foo<T>::bar I believe that the reason for this is that such deduction is not possible in general; 我认为,这样做的原因是通常不可能进行这种扣除。 there can always be partial specializations of Foo that define bar to be some arbitrarily complicated typedef. Foo总是存在一些局部专业,它们将bar定义为任意复杂的typedef。

The workaround is to define the nested type as an unnested type then bring it in using a typedef , but use the original unnested name for deduction: 解决方法是将嵌套类型定义为非嵌套类型,然后使用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);

In your specific case the nested type B is uniquely attached to the specific specialization of the enclosing type A . 在您的特定情况下,嵌套类型B唯一地附加到封闭类型A的特定专业领域。 There's one-to-one correspondence between various B s and their enclosing A s. 各个B与它们所包围的A之间存在一一对应的关系。 So, theoretically it should be possible to deduce the arguments of A from a specific B . 因此,理论上应该有可能从特定的B推导出A的参数。

However, in general case the nested type name might refer to an alias (eg typedef-name), as opposed to a genuinely new type name (as in your example). 但是,通常情况下,嵌套类型名称可能引用别名 (例如typedef-name),而不是真正的新类型名称(如您的示例)。 In case of nested alias the 1:1 correspondence no longer holds, which is demonstrated by the examples in other answers. 在嵌套别名的情况下,1:1对应关系不再成立,这在其他答案中的示例中得到了证明。

The language specification does not distinguish between these two situations (a genuinely new nested type vs. a nested alias), so it opts for the "common denominator" approach and just always treats the enclosing template parameters as non-deduced context . 语言规范没有区分这两种情况( 全新的嵌套类型与嵌套别名),因此它选择“公分母”方法,并且始终将封闭的模板参数视为非推导上下文

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么不能推导嵌套在模板类中的枚举的模板参数? - Why can't the template parameters for enums nested in a template class be deduced? 模板化函数中的模板参数 - template parameters in templated type function 可以推断出模板函数中的参数类型吗? - Can the types of parameters in template functions be inferred? 为什么我不能使用模板化类来专门化类模板? - Why can't I specialize class template with a templated class? Is there a clean way to forward template parameters to a templated function? - Is there a clean way to forward template parameters to a templated function? 为什么不能用结构定义模板? - Why can't you define a template with a struct? 无法在派生的模板化类中使用struct? - Can't use struct in derived templated class? 模板化函数可以作为另一个函数的模板参数吗? - Can a templated function be a template argument to another function? 模板化的用法无法选择模板函数用作Visual Studio中的参数 - Templated usings Can't Select Template Functions to use as Parameters in Visual Studio 由于模板参数中的逗号,无法使用模板化类型编译va_arg()调用 - Can't compile va_arg() call using templated type because of comma in template parameters
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM