【发布时间】:2019-01-02 17:26:38
【问题描述】:
我有一个模板类和一个模板返回类型的函数:
template<typename T>
class Wrapper {
public:
Wrapper(const T& _data) : data(_data) { }
const T& get_data() {return data;};
private:
T data;
};
template <typename T>
Wrapper<T> build_wrapped(){
T t{};
return Wrapper<T>(t);
}
假设我想为一种特定类型 T 扩展返回的 Wrapper 并为该类型专门化 build_wrapped() 函数。所以,让我们创建一个模板来保存返回类型并在build_wrapped() 中使用它:
template<typename T>
struct ReturnType {
using type = Wrapper<T>;
};
template <typename T>
typename ReturnType<T>::type build_wrapped(){
T t{};
return typename ReturnType<T>::type(t);
}
并用它来提供专业化:
struct Foo{};
class ExtendedWrapper : public Wrapper<Foo> {
public:
ExtendedWrapper(const Foo& _data) : Wrapper(_data) {}
int get_answer() {return 42;};
};
template<>
struct ReturnType<Foo> {
using type = ExtendedWrapper;
};
template<>
typename ReturnType<Foo>::type build_wrapped(){
Foo t{};
return typename ReturnType<Foo>::type(t);
}
但是,最终声明被 gcc 和 clang 拒绝。例如,clang 返回:
错误:没有函数模板与函数模板特化匹配 'build_wrapped'
注意:候选模板被忽略:无法推断模板参数“T”
我可以通过为Foo 创建一个明确的Wrapper 特化来绕过使用ReturnType。但是,当我只想添加一些新功能时(如在ExtendedWrapper 中),这需要复制Wrapper 中的所有代码(在我的现实生活中这是一个实质性的类)。那么,这可以做到吗?上面的方法有什么问题?
【问题讨论】:
-
另一种方法是使用标签,然后使用重载::
template <typename T> struct tag{}; template <typename T> Wrapper<T> build_wrapped(tag<T>) { return Wrapper<T>{{}};} ExtendedWrapper build_wrapped(tag<Foo>) { return ExtendedWrapper{{}};}.
标签: c++ templates template-specialization specialization