模板化结构内的模板化结构的模板特化失败

时间:2015-12-14 16:27:08

标签: c++ templates c++11 partial-specialization

我似乎无法解决以下示例出现的问题

$ 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__显示Functor1&amp;的相同签名。实例化时Functort2

任何人都可以解释这种行为吗?有没有办法修复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>]

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

2 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:2)

永远不会使用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。因此,在任何情况下都无法毫不含糊地推断出它。