模板的模板函数特化 class
Template function specialization for template class
是否可以在 C++11/14 中编写类似的东西?
#include <iostream>
#include <vector>
template <typename T>
T Get();
template <typename T>
struct Data {
std::vector<T> data;
};
template <>
template <typename T>
Data<T> Get<Data<T>>() {
return Data<T>{{T{}, T{}}};
}
template <>
template <typename T>
std::vector<T> Get<std::vector<T>>() {
return std::vector<T>(3);
}
int main() {
std::cout << Get<Data<int>>().data.size() << std::endl; // expected output is 2
std::cout << Get<std::vector<int>>().size() << std::endl; // expected output is 3
return 0;
}
重载在这种情况下无济于事,因为对 Get<...>()
的调用将不明确 (see):
template <typename T>
Data<T> Get() {
return Data<T>{{T{}, T{}}};
}
template <typename T>
std::vector<T> Get() {
return std::vector<T>(3);
}
欢迎任何关于如何克服这个问题的指导。
有一个解决方法,它给你这样的东西:不要专门化 - 过载:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
template <typename T>
size_t Get(const T& data)
{
return 444;
}
template <typename T>
struct Data
{
std::vector<T> data;
};
template <typename T>
size_t Get(const Data<T>& data) {
return data.data.size();
}
int main() {
std::cout << Get<>(0) << std::endl; // expected output is 444
std::cout << Get<>(Data<int>{}) << std::endl; // expected output is 0
return 0;
}
输出:
444
0
请注意,size_t Get(const Data<T>& data)
不是专业化 - 它完全是 "different" Get()
,对于任何 T
类型的 Data<T>
参数调用].
Here 你可以看到工作示例。
编辑
我看到你完全改变了你的问题。但是,我仍然会尝试回答它。对于缺少部分函数专业化,有一个标准的解决方法——使用对 structs/classes.
的委托
这是您需要的:
#include <iostream>
#include <vector>
using namespace std;
template <typename T>
struct GetImpl;
template <typename T>
struct Data {
std::vector<T> data;
};
template <typename T>
struct GetImpl< Data<T> >
{
static Data<T> Get() {
return Data<T>{ {T{}, T{}} };
};
};
template <typename T>
struct GetImpl< std::vector<T> >
{
static std::vector<T> Get() {
return std::vector<T>(3);
};
};
int main() {
std::cout << GetImpl< Data<int> >::Get().data.size() << std::endl; // expected output is 2
std::cout << GetImpl< std::vector<int> >::Get().size() << std::endl; // expected output is 3
return 0;
}
输出:
2
3
Working sample can be found here.
如果您不喜欢这种语法,可以通过将静态函数 Get()
更改为函数调用运算符来使其更短一些:
template <typename T>
struct Get< Data<T> >
{
Data<T> operator()() {
return Data<T>{ {T{}, T{}} };
};
};
template <typename T>
struct Get< std::vector<T> >
{
std::vector<T> operator()() {
return std::vector<T>(3);
};
};
然后:
Get< Data<int> >()().data.size();
Get< std::vector<int> >()().size();
您只有两个额外的字符 - ()
。这是我能想到的最短的解决方案。
But it would be impossible for compiler to distinguish Get<Data<int>>
from Get<Data<Data<int>>>
.
并非不可能。如果这是您需要做的事情,我们可以添加单独的重载:
template <typename T>
size_t Get(const Data<T>& data);
template <typename T>
size_t Get(const Data<Data<T>>& data); // preferred for Data<Data<int>>
或者,如果您想要的是 仅 非嵌套情况的重载,我们可以添加类型特征并使用 SFINAE:
template <typename T> struct is_data : std::false_type { };
template <typename T> struct is_data<Data<T>> : std::true_type { };
template <typename T>
enable_if_t<!is_data<T>::value, size_t>
Get(const Data<T>& data);
这样,使用 Data<Data<int>>
的调用将调用通用 Get(const T&)
。或者,如果您希望该案例根本不编译:
template <typename T>
size_t Get(const Data<T>& data) {
static_assert(!is_data<T>::value, "disallowed");
...
}
所以重载给了你很多选择。专业化给你 none,因为它无论如何都是不允许的。
正如 Columbo 在他的评论中提到的,您应该应用标准解决方法来解决函数缺少部分特化支持的问题:委派给部分特化的 class:
template <typename T>
struct GetImpl;
template <typename T>
T Get() { return GetImpl<T>::Do(); }
现在在 struct GetImpl<T> { static T Do(); }
上使用部分专业化而不是 Get<T>()
按照对结构的方式进行委托,您可以实现更通用的方法:您可以使用结构来检查容器类型和内部类型,如下所示:
#include <iostream>
#include <vector>
template <typename T>
struct Data {
std::vector<T> data;
};
template <template <typename...> class Container, typename>
struct get_inner;
template <template <typename...> class Container, typename T>
struct get_inner<Container, Container<T>>
{
typedef T type;
};
template <typename T, typename U = typename get_inner<Data, T>::type>
Data<U> Get() {
return Data<U>{ {U{}, U{}} };
}
template <typename T, typename U = typename get_inner<std::vector, T>::type>
std::vector<U> Get() {
return std::vector<U>(3);
}
int main() {
std::cout << Get<Data<int>>().data.size() << std::endl; // expected output is 2
std::cout << Get<std::vector<int>>().size() << std::endl; // expected output is 3
return 0;
}
是否可以在 C++11/14 中编写类似的东西?
#include <iostream>
#include <vector>
template <typename T>
T Get();
template <typename T>
struct Data {
std::vector<T> data;
};
template <>
template <typename T>
Data<T> Get<Data<T>>() {
return Data<T>{{T{}, T{}}};
}
template <>
template <typename T>
std::vector<T> Get<std::vector<T>>() {
return std::vector<T>(3);
}
int main() {
std::cout << Get<Data<int>>().data.size() << std::endl; // expected output is 2
std::cout << Get<std::vector<int>>().size() << std::endl; // expected output is 3
return 0;
}
重载在这种情况下无济于事,因为对 Get<...>()
的调用将不明确 (see):
template <typename T>
Data<T> Get() {
return Data<T>{{T{}, T{}}};
}
template <typename T>
std::vector<T> Get() {
return std::vector<T>(3);
}
欢迎任何关于如何克服这个问题的指导。
有一个解决方法,它给你这样的东西:不要专门化 - 过载:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
template <typename T>
size_t Get(const T& data)
{
return 444;
}
template <typename T>
struct Data
{
std::vector<T> data;
};
template <typename T>
size_t Get(const Data<T>& data) {
return data.data.size();
}
int main() {
std::cout << Get<>(0) << std::endl; // expected output is 444
std::cout << Get<>(Data<int>{}) << std::endl; // expected output is 0
return 0;
}
输出:
444
0
请注意,size_t Get(const Data<T>& data)
不是专业化 - 它完全是 "different" Get()
,对于任何 T
类型的 Data<T>
参数调用].
Here 你可以看到工作示例。
编辑
我看到你完全改变了你的问题。但是,我仍然会尝试回答它。对于缺少部分函数专业化,有一个标准的解决方法——使用对 structs/classes.
的委托这是您需要的:
#include <iostream>
#include <vector>
using namespace std;
template <typename T>
struct GetImpl;
template <typename T>
struct Data {
std::vector<T> data;
};
template <typename T>
struct GetImpl< Data<T> >
{
static Data<T> Get() {
return Data<T>{ {T{}, T{}} };
};
};
template <typename T>
struct GetImpl< std::vector<T> >
{
static std::vector<T> Get() {
return std::vector<T>(3);
};
};
int main() {
std::cout << GetImpl< Data<int> >::Get().data.size() << std::endl; // expected output is 2
std::cout << GetImpl< std::vector<int> >::Get().size() << std::endl; // expected output is 3
return 0;
}
输出:
2
3
Working sample can be found here.
如果您不喜欢这种语法,可以通过将静态函数 Get()
更改为函数调用运算符来使其更短一些:
template <typename T>
struct Get< Data<T> >
{
Data<T> operator()() {
return Data<T>{ {T{}, T{}} };
};
};
template <typename T>
struct Get< std::vector<T> >
{
std::vector<T> operator()() {
return std::vector<T>(3);
};
};
然后:
Get< Data<int> >()().data.size();
Get< std::vector<int> >()().size();
您只有两个额外的字符 - ()
。这是我能想到的最短的解决方案。
But it would be impossible for compiler to distinguish
Get<Data<int>>
fromGet<Data<Data<int>>>
.
并非不可能。如果这是您需要做的事情,我们可以添加单独的重载:
template <typename T>
size_t Get(const Data<T>& data);
template <typename T>
size_t Get(const Data<Data<T>>& data); // preferred for Data<Data<int>>
或者,如果您想要的是 仅 非嵌套情况的重载,我们可以添加类型特征并使用 SFINAE:
template <typename T> struct is_data : std::false_type { };
template <typename T> struct is_data<Data<T>> : std::true_type { };
template <typename T>
enable_if_t<!is_data<T>::value, size_t>
Get(const Data<T>& data);
这样,使用 Data<Data<int>>
的调用将调用通用 Get(const T&)
。或者,如果您希望该案例根本不编译:
template <typename T>
size_t Get(const Data<T>& data) {
static_assert(!is_data<T>::value, "disallowed");
...
}
所以重载给了你很多选择。专业化给你 none,因为它无论如何都是不允许的。
正如 Columbo 在他的评论中提到的,您应该应用标准解决方法来解决函数缺少部分特化支持的问题:委派给部分特化的 class:
template <typename T>
struct GetImpl;
template <typename T>
T Get() { return GetImpl<T>::Do(); }
现在在 struct GetImpl<T> { static T Do(); }
上使用部分专业化而不是 Get<T>()
按照对结构的方式进行委托,您可以实现更通用的方法:您可以使用结构来检查容器类型和内部类型,如下所示:
#include <iostream>
#include <vector>
template <typename T>
struct Data {
std::vector<T> data;
};
template <template <typename...> class Container, typename>
struct get_inner;
template <template <typename...> class Container, typename T>
struct get_inner<Container, Container<T>>
{
typedef T type;
};
template <typename T, typename U = typename get_inner<Data, T>::type>
Data<U> Get() {
return Data<U>{ {U{}, U{}} };
}
template <typename T, typename U = typename get_inner<std::vector, T>::type>
std::vector<U> Get() {
return std::vector<U>(3);
}
int main() {
std::cout << Get<Data<int>>().data.size() << std::endl; // expected output is 2
std::cout << Get<std::vector<int>>().size() << std::endl; // expected output is 3
return 0;
}