如何在任意依赖类型上专门化模板
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>
是否有 所有可能的 T
s 并找出是否有任何一个他们有一个嵌套的 typedef type
别名 int
。这不可能发生,因为 "all possible T
s" 的集合是无限的。 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;
}
我对问题的理解正确吗?
说,我有一些专门用于几种类型的模板,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>
是否有 所有可能的 T
s 并找出是否有任何一个他们有一个嵌套的 typedef type
别名 int
。这不可能发生,因为 "all possible T
s" 的集合是无限的。 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;
}
我对问题的理解正确吗?