说,我有一些专门针对几种类型的模板TypeMathcer,它具有type成员。

#include <memory>
#include <vector>

template <typename T>
struct TypeMatcher;

template <typename T>
struct TypeMatcher<T *>
{
    // making some type from T
    typedef std::shared_ptr<T> type;
};

template <typename T>
struct TypeMatcher<T&>
{
    // making other type from T
    typedef std::vector<T> type;
};

现在,我想创建另一个模板,并将其专门用于从TypeMatcher获得的类型。如果我直接做到这一点
template <typename T>
struct MyNeedfullTemplate;

template <typename T>
struct MyNeedfullTemplate<typename TypeMatcher<T>::type>
{
};

我收到编译器错误:template parameters not deducible in partial specialization

如果使用using语法,则出现相同的错误
template <typename T>
using type_matcher_t = typename TypeMatcher<T>::type;

template <typename T>
struct MyNeedfullTemplate;

template <typename T>
struct MyNeedfullTemplate<type_matcher_t<T> >
{
};

我阅读的问题partial specialization for iterator type of a specified container type的答案与我的问题非常相似,但仍不确定是否存在一个反例使所有问题变得毫无意义。现在我们还拥有全新的c++ 14和c++ 17标准,这些标准可能会改变现状。那么,如果我确保特化是唯一且存在的,那么使参数可推论的可能性将最大吗?

最佳答案

从原则上讲,这是不可能的,没有任何花哨的C++ 9999可以改变它。

您要编译器执行的操作:

代码中有MyNeedfulTemplate<int>这样的用法。编译器需要为MyNeedfulTemplate<U>定义U = int。您尝试提供表格的部分特化

template <typename T>
struct MyNeedfullTemplate<typename TypeMatcher<T>::type>

要查看该特化是否适用,编译器将必须检查TypeMatcher<T>中所有可能的T和中的,并查找其中是否有嵌套的typedef type作为int的别名。这不可能发生,因为“所有可能的T s”的集合是无限的。好的,TypeMatcher<int>没有这种类型,TypeMatcher<int*>TypeMatcher<int**>TypeMatcher<int***>也没有。但是,如果TypeMatcher<int****>呢?最好继续尝试...

还请记住存在部分和完全特化,这意味着TypeMatcher本身可以被特化。

简而言之,如果您只有int而不是TypeMatcher<X>::type,则无法将int链接到X

您应该可以通过稍微重构(反转)TypeMatcher来达到类似的目的:
template <class T>
struct TypeMatcher2
{
  static constexpr specialised = false;
};

template <class T>
struct TypeMatcher2<std::shared_ptr<T>>
{
  static constexpr specialised = true;
  using OldType = T*;
};

template <class T>
struct TypeMatcher2<std::vector<T>>
{
  static constexpr specialised = true;
  using OldType = T&;
}

template <class T, bool spec = TypeMatcher2<T>::specialised>
struct MyNeedfullTemplate
{
  // generic version
};

template <class T>
struct MyNeedfullTemplate<T, true>
{
  using OriginalT = typename TypeMatcher2<T>::OldType;

  // specialised version
};

10-08 14:06