我上了复数类:
template<typename T>
struct Complex{
T r;
T i;
};
我决定添加类似于std::get
的功能:
template<int X, typename T>
T get(const Complex<T> &a){
switch(X){
case 0: return a.r;
case 1: return a.i;
}
}
这正常。我也知道编译器可以优化它。
然后我决定以其他方式重写它:
template<int X,typename T>
T get(const Complex<T> &a);
template<typename T>
constexpr T get<0, T>(const Complex<T> &a){
return a.r;
}
template<typename T>
constexpr T get<1, T>(const Complex<T> &a){
return a.i;
}
但是这无法编译,我很好奇实现的正确性如何?
我试图检查std::get
的制作方法,但找不到任何“可读”的东西。
答案 0 :(得分:3)
在C ++ 11中,您可以像这样实现此练习:
#include <type_traits>
template<typename T>
struct Complex{
T r;
T i;
};
template<int X, typename T>
constexpr typename std::enable_if<X == 0,T>::type
get(const Complex<T> &a){
return a.r;
}
template<int X, typename T>
constexpr typename std::enable_if<X == 1,T>::type
get(const Complex<T> &a){
return a.i;
}
Partial template specialization适用于 类模板,而不是功能模板。
在C ++ 14中,您可以使用std::enable_if_t
编写更加简洁的代码。
在C ++ 17中,您可以使用if constexpr
来编写单个函数模板,而不是
SFINAE重载。
答案 1 :(得分:1)
功能模板不能部分专门化。
另一种方法是 tag dispatch ,它使用函数重载达到类似的效果:
template<int X>
using Int = std::integral_constant<int, X>;
template<typename T> inline T get(const Complex<T> &a, Int<0>) { return a.r; }
template<typename T> inline T get(const Complex<T> &a, Int<1>) { return a.i; }
template<int X, typename T>
inline T get(const Complex<T> &a) { return get(a, Int<X>{}); }
答案 2 :(得分:0)
我能够解决这个问题,但是对于这样一个简单的任务来说,它看起来非常复杂:
namespace complex_impl__{
template<int X, typename T>
struct GetHelper{
static T get(const Complex<T> &a);
};
template<typename T>
struct GetHelper<0, T>{
constexpr static T get(const Complex<T> &a){
return a.r;
}
};
template<typename T>
struct GetHelper<1, T>{
constexpr static T get(const Complex<T> &a){
return a.i;
}
};
}
template<int I,typename T>
constexpr T get(const Complex<T> &a){
return complex_impl__::GetHelper<I, T>::get(a);
}
然后,我能够将T
移至get()
方法中,因此可以减少代码量:
namespace complex_impl__{
template<int I>
struct GetHelper{
template<typename T>
static T get(const Complex<T> &a);
};
template<>
struct GetHelper<0>{
template<typename T>
constexpr static T get(const Complex<T> &a){
return a.r;
}
};
template<>
struct GetHelper<1>{
template<typename T>
constexpr static T get(const Complex<T> &a){
return a.i;
}
};
}
template<int I,typename T>
constexpr T get(const Complex<T> &a){
return complex_impl__::GetHelper<I>::get(a);
}
一个人可以“剥离”整个template<int I> struct GetHelper
类:
namespace complex_impl__{
template<int I>
struct GetHelper;
template<>
struct GetHelper<0>{
template<typename T>
constexpr static T get(const Complex<T> &a){
return a.r;
}
};
template<>
struct GetHelper<1>{
template<typename T>
constexpr static T get(const Complex<T> &a){
return a.i;
}
};
}
template<int I,typename T>
constexpr T get(const Complex<T> &a){
return complex_impl__::GetHelper<I>::get(a);
}
答案 3 :(得分:0)
问题是您不能对功能模板进行部分专业化。请阅读 C++ template specialisation of function和Getting “illegal use of explicit template arguments” when doing a pointer partial specialization for a class method,尼克描述了相同的解决方案。
要使模板专业化工作,请参阅尼克的答案。
您的解决方案看起来确实不错,
我只是将开关更改为if constexpr
。
#include <iostream>
template<typename T>
struct Complex
{
T r;
T i;
};
template<int X, typename T>
constexpr T get(const Complex<T> &a)
{
if constexpr(X == 0)
{
return a.r;
}
else if constexpr (X == 1)
{
return a.i;
}
}
int main()
{
Complex<int> test;
test.r = 1;
test.i = 12;
std::cout << get<0>(test) << std::endl;
std::cout << get<1>(test) << std::endl;
std::cin.get();
}