如何在任意依赖类型上专门化模板

How to specialize template on arbitrary dependent type

说,我有一些专门用于几种类型的模板,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>等用法。编译器需要为 U = int 定义 MyNeedfulTemplate<U>。您已尝试提供

形式的部分专业化
template <typename T>
struct MyNeedfullTemplate<typename TypeMatcher<T>::type>

要查看此特化是否适用,编译器必须检查 TypeMatcher<T> 是否有 所有可能的 Ts 并找出是否有任何一个他们有一个嵌套的 typedef type 别名 int。这不可能发生,因为 "all possible Ts" 的集合是无限的。 OK,TypeMatcher<int>没有这样的类型,TypeMatcher<int*>TypeMatcher<int**>TypeMatcher<int***>也没有。但是如果 TypeMatcher<int****> 呢?最好继续尝试...

还要记住存在部分和完全专业化,这意味着 TypeMatcher 本身可以专业化。

简而言之,如果您只有 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
};

我想你想做的是:

#include <iostream>

#include <memory>
#include <vector>
#include <utility>

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


template <typename T, typename = void>
struct MyNeedfullTemplate;

template <typename T>
struct MyNeedfullTemplate<TypeMatcher<T>, std::enable_if_t<std::is_same<typename TypeMatcher<T>::type, std::vector<std::remove_reference_t<T>>>::value>>
{
    static void report() { std::cout << "hello" << std::endl; }
};
int main()
{
    using matcher_type = TypeMatcher<int&>;
    using full_type = MyNeedfullTemplate<matcher_type>;
    full_type::report();

    return 0;
}

我对问题的理解正确吗?