模板化结构内的模板化结构的模板专业化失败

Template specialisation failure for a templated structure inside a templated structure

我似乎无法理解以下示例出了什么问题

$ cat repro.cpp
#include <iostream>
using namespace std;

template<class T>
struct S1_t
{
  template<class U>
  struct inner_t_x {};

  using inner_t = inner_t_x<T>;
};
struct Bogus{};

template<class T>
struct Functor1
{
  void operator()() 
  {
    cout << "Functor1 FAIL: " << __PRETTY_FUNCTION__ << endl;
  }
};
template<>
struct Functor1<typename S1_t<Bogus>::template inner_t_x<Bogus>>
{
  void operator()() 
  {
    cout << "Functor1 PASS: " << __PRETTY_FUNCTION__ << endl;
  }
};

template<class T>
struct Functor2
{
  void operator()() 
  {
    cout << "Functor2 FAIL: " << __PRETTY_FUNCTION__ << endl;
  }
};
template<class T>
struct Functor2<typename S1_t<T>::template inner_t_x<T>>
{
  void operator()() 
  {
    cout << "Functor2 PASS: " << __PRETTY_FUNCTION__ << endl;
  }
};

template<class T>
void eval()
{
  Functor1<T>{}();
  Functor2<T>{}();
}

int main()
{
  eval<S1_t<Bogus>::inner_t>();
  return 0;
}

$ clang++ repro.cpp -std=c++11 -Wall && ./a.out
Functor1 PASS: void Functor1<S1_t<Bogus>::inner_t_x<Bogus> >::operator()()
Functor2 FAIL: void Functor2<S1_t<Bogus>::inner_t_x<Bogus> >::operator()() [T = S1_t<Bogus>::inner_t_x<Bogus>]

Functor1 中,我明确地专注于类型 Bogus,并且确实正在调用该专业化。但是,在 Functor2 中允许推导类型,但部分特化失败,而是实例化通用模板。然而,__PRETTY_PRINT__ 在实例化时为 Functor1Functort2 显示相同的签名。

任何人都可以解释这种行为吗?有没有办法修复 Functor2 部分专业化以适应这种情况?谢谢!

fwiw:将 Functor2 部分专业化更改为

template<class T>
struct Functor2<typename S1_t<Bogus>::template inner_t_x<T>>
{
  void operator()() 
  {
    cout << "Functor2 PASS: " << __PRETTY_FUNCTION__ << endl;
  }
};

给出正确的输出

Functor1 PASS: void Functor1<S1_t<Bogus>::inner_t_x<Bogus> >::operator()()
Functor2 PASS: void Functor2<S1_t<Bogus>::inner_t_x<Bogus> >::operator()() [T = S1_t<Bogus>::inner_t_x<Bogus>]

但这不是我的用例中的选项。

typename S1_t<T>::..在偏特化中不可推导。

当您使用 inner_t 而不是 inner_t_x<T> 时出现了更清晰的错误:

main.cpp:41:8: error: template parameters not deducible in partial specialization:

 struct Functor2<typename S1_t<T>::inner_t>

        ^

main.cpp:41:8: note:         'T'

main.cpp:41:8: warning: class template partial specialization contains a template parameter that cannot be deduced; this partial specialization will never be used

永远不会使用 Functor2 的特化。编译器可能会发出警告,但在您的情况下不会。它不可推导的原因很简单:假设您稍后添加类似

的内容
struct Hogus;

template<>
struct S1_t<Hogus>
{
  template <typename U>
  using inner_t_x = S1_t<Bogus>::inner_t_x<Bogus>;
};

那么 S1_t<Bogus>::inner_t_x<Bogus>S1_t<Hogus>::inner_t_x<Hogus> 将是同一类型。因此,Functor2 的偏特化中的模板推导可以产生 T=BogusT=Hogus。因此,在任何情况下都不能明确地推导出来。