对于模板功能,我们可以按如下方式对其进行专门化:
template <typename T>
void func(T t) {}
// specialization for int
template <>
void func(int t) {}
但是,我不确定如何使用通用引用(来自run-sequence的名称)来专门化模板函数。
// template function with universal reference
template <typename T>
void func(T &&t) {}
我认为简单地将T
替换为int
并不能使其成为专业化:
template <>
void func(int &&t) {}
由于模板功能可以同时接受左值和右值,而“#”专用&#39;一个人只能接受右值。
我是否还应该定义一个&#39;专业化&#39;左值参考?
// 'specialization' for lvalue reference
template <>
void func(int &t) {}
这两个专业&#39;对原始模板功能进行专门化?或者对它有专业化是否有意义?
答案 0 :(得分:4)
专业化功能模板很少是个好主意。非常稀有。它看起来像模板类专门化和重载的混合,但两者都没有。
函数有重载。使用那些。
如果重载没有得到您想要的确切行为,请使用基于重载的标记调度的辅助函数,或转发到类。
在这种情况下,它可以像:
一样简单template <typename T>
void func(T&&){}
void func(int){}
或者:
template<class T>struct tag_t{};
template<class T>constexpr tag_t<T>tag{};
namepsace details{
template <class T, class U>
void func(tag_t<T>, U&&){}
template <class U>
void func(tag_t<int>, U&&){}
}
template <class T>
void func(T&&t){
return details::func(tag<std::decay_t<T>>, std::forward<T>(t));
}
答案 1 :(得分:2)
当T与某个类型匹配时,它可以是任何一个(这是一个非详尽的列表):
int
int&
int const&
int&&
int volatile&
int volatile const&
......等等。
在这种情况下专注并没有多大意义,因为我们必须预测和编写符合所有用例的专业化。
但也许func
实际上代表了一些可以应用于通用引用的函数的概念。
在这种情况下,我们可能做的是这样的事情:
#include <iostream>
template<class Type>
struct func_op
{
template<class T> void operator()(T&& t) const
{
// default implementation
}
};
template <typename T>
void func(T&& t)
{
func_op<std::decay_t<T>> op;
return op(std::forward<T>(t));
}
// now specialise the operation for all classes of int
template<>
struct func_op<int>
{
template<class T> void operator()(T&& t) const
{
static_assert(std::is_same<std::decay_t<T>, int>(),
"not an int!");
std::cout << "some kind of operation on int" << t << std::endl;
}
};
int main()
{
int a = 5;
const int b = 6;
const volatile int c = 7;
volatile int d = 8;
func(a);
func(b);
func(c);
func(d);
func(std::move(a));
func(std::move(b));
func(std::move(c));
func(std::move(d));
}
此处,Type
专门化中的func_op<>
模板参数表示常规值类型。然后,我们提供模板operator()
,以提供基于参考的通用实现。
T
中的func<T>
被转换为&#39;一般值类型&#39;通过std::decay_t
- 它具有剥离所有const,volatile和引用修饰符并使我们留下原始类型(例如int)的效果。
如果我们希望为(例如)const int refs提供特殊处理,我们可以进一步专门化或重载operator()。