比方说,我们需要一个函数模板,该模板应根据类型返回整数:
template<typename T>
int get_type();
此外,我们将其专门化为几种类型:
template<>
int get_type<int>()
{
return TYPE_INT;
}
// And so on for other types...
这很好用,但不适用于数组类型。我可以执行以下操作:
template<>
int get_type<char[]>()
{
return TYPE_STRING;
}
,编译器对此表示“同意”,但链接器不同意。因为类型char[]
不同于例如char[5]
。
有什么方法可以在没有功能参数的情况下实现功能模板?也就是说,我知道我们可以做这样的事情:
template<typename T>
int get_type(const T&);
但是,实际上,这里不需要(使用)功能参数。
编辑:
我使用C ++ 11。
答案 0 :(得分:9)
您不能对模板函数进行部分专业化(但是您可以对模板类进行专门化
)另一种方法是使用重载而不是专门化来进行标签分配:
template <typename> struct Tag{};
constexpr int get_type(Tag<int>) { return TYPE_INT; }
template <std::size_t N>
constexpr int get_type(Tag<char[N]>) { return TYPE_STRING; }
template <typename T>
constexpr int get_type() { return get_type(Tag<T>{}); }
答案 1 :(得分:8)
您需要部分专业化才能解决可变数组长度的问题,并且C ++不允许部分专业化的功能模板。规范的解决方案是(部分)专门化具有(静态)成员(函数)的类模板,并从您未专门设计的函数模板中将其分发给您:
namespace detail {
template <typename T>
struct get_type;
template <>
struct get_type<int> {
static constexpr int value = TYPE_INT;
};
template <>
struct get_type<char> {
static constexpr int value = TYPE_CHAR;
};
template <typename T, std::size_t N>
struct get_type<T[N]> {
static constexpr int value = get_type<T>::value | TYPE_ARRAY;
};
template <std::size_t N>
struct get_type<char[N]> {
static constexpr int value = TYPE_STRING;
};
} // namespace detail
template<typename T>
constexpr int get_type() {
return detail::get_type<T>::value;
}
答案 2 :(得分:6)
您不能部分专用于具有大小的数组的函数。但是您可以在课堂上做到这一点。
template<typename T>
class type
{
static int get_type();
};
template<>
struct type<int>
{
static int get_type() { return 1; }
};
template<size_t SZ>
struct type<char[SZ]>
{
static int get_type() { return 2; }
};
template<typename T>
int get_type() { return type<T>::get_type(); }
int main()
{
std::cout << get_type<char[3]>() << std::endl;
return 0;
}
答案 3 :(得分:3)
我认为Konrad已经描述了最佳方法。
这是由SFINAE提供支持的另一种具有超载和专业化的方法
// overload 1, for non-array types
template<typename T>
std::enable_if_t<!std::is_array_v<T>, int> get_type();
// specialization of overload 1 for int
template <>
auto get_type<int>() -> int {
return 1;
}
// overload 2, for array types
template <typename T>
auto get_type() -> std::enable_if_t<std::is_array_v<T>, int> {
return 3;
}