对数组参数的引用很有用,因为它可以防止衰减,从而可以推断出数组的大小。
template <typename T, std::size_t N>
constexpr std::size_t array_size(T (&) [N]) noexcept
{
return N;
}
但这什么时候有用?
template<typename T>
void foo(T& t)
{
// we now have a reference to bar
}
void bar() { }
int main()
{
foo(bar);
}
我们什么时候关心防止指针衰减的功能?我问这个有用的时间,而不是为什么它不被禁止。
答案 0 :(得分:3)
与对象一样,如果“没有对象”(“无功能”)是一个合理的值,我们指向一个指针,如果我们希望确保(除非有人坚持用脚射击自己),总会有一个参考一个有效的对象(函数)引用。
考虑以下穷人的功能包装(富人去over there)。
template<typename>
class Function; // never defined
template<typename ReturnT, typename... ArgT>
class Function<ReturnT(ArgT...)>
{
private:
ReturnT (*func_)(ArgT...);
public:
// Will also accept a 'nullptr'
Function(ReturnT (*func)(ArgT...)) noexcept : func_ {func}
{
}
ReturnT
operator()(ArgT... args)
{
return this->func_(args...);
}
};
现在我们可以编写以下程序,该程序运行正常。
#include <iostream>
int
add(int a, int b)
{
return a + b;
}
int
main()
{
Function<int(int, int)> f {add}; // ok
std::cout << f(5, 7) << std::endl; // ok, prints 12
}
但是,我们也可以编写以下程序,但该程序并不好用。
int
main()
{
Function<int(int, int)> f {nullptr}; // compiles fine
std::cout << f(5, 7) << std::endl; // compiles fine, crashes at run-time
}
相反,如果我们在模板的定义中将(*func)
替换为(&func)
,
// Won't accept a 'nullptr'
Function(ReturnT (&func)(ArgT...)) noexcept : func_ {func}
{
}
行
Function<int(int, int)> f {nullptr}; // compile-time error
会触发编译时错误。
答案 1 :(得分:0)
对我而言,区别在于普通变量引用和指针之间。参考文献比指针更好处理。
当我自定义算法的某些部分时,我有一个用例。它有一些阶段,我可以在每个阶段的几个选项之间切换。这当然可以用指针实现,但是嘿,你可以在任何地方使用指针代替引用。
看起来与此相似:
#include <iostream>
using namespace std;
class Foo
{
public:
Foo(void(&t)()) : barish(t) { };
void fun() {barish();};
private:
void(&barish)();
};
void bar() { cout << "meow\n";}
void bark() { cout << "woof\n";}
int main()
{
Foo foo1(bar);
Foo foo2(bark);
foo1.fun();
foo2.fun();
}
您可以自定义fun
并且不必处理解除引用并断言它不为空。