这就是 C++:缺少in
和out
参数并不意味着该语言有缺陷,这意味着您需要实现其他语言作为库的语言特性所做的事情。
创建两个template
类和函数。
in_param<T>
是 a 的包装器T const&
,而 whilieio_param<T>
是T&
引用的包装器。您可以通过调用辅助函数in
和io
.
在内部,它们的行为类似于引用(通过重载)。
在外部,调用者必须调用in
或io
在参数上,在调用点标记它。
out
更棘手:在函数内部,只有赋值是合法的。理想情况下,我们甚至不会构造它:一种emplace
方法可能会有所帮助。
但是,调用者需要一些通道来知道参数是否被构造。
我要做的out_param
只是 has operator=
,并且它分配。 out
将某些东西包装成out_param
. 如果您想要延迟构造,请optional
在接近的 out 参数内部使用。也许out_param
还有 has emplace
,通常只是分配,但如果 tyoe 包裹的 hasemplace
调用它呢?
template<typename T>
struct in_param : std::reference_wrapper<T const> {
explicit in_param( T const& t ):std::reference_wrapper<T const>(t) {}
in_param( in_param<T>&& o ):std::reference_wrapper<T const>(std::move(o)) {}
void operator=( in_param<T> const& o ) = delete;
};
template<typename T>
struct io_param : std::reference_wrapper<T> {
explicit io_param( T& t ):std::reference_wrapper<T>(t) {}
io_param( io_param<T>&& o ):std::reference_wrapper<T>(std::move(o)) {}
};
template<typename T>
in_param< T > in( T const& t ) { return in_param<T>(t); }
template<typename T>
io_param< T > io( T& t ) { return io_param<T>(t); }
template<typename T>
struct out_param {
private:
T& t;
public:
out_param( T& t_ ):t(t_) {}
out_param( out_param<T>&& o ):t(o.t) {}
void operator=( out_param<T> const& o ) = delete;
void operator=( out_param<T> && o ) = delete;
void operator=( out_param<T> & o ) = delete;
void operator=( out_param<T> && o ) = delete;
template<typename U>
out_param<T>& operator=( U&& u ) {
t = std::forward<U>(u);
return *this;
}
// to improve, test if `t` has an `emplace` method. If it does not,
// instead do t = T( std::forward<Us>(us)... ). (I'd use tag dispatching
// to call one of two methods)
template<typename... Us>
void emplace( Us&&... us ) {
t.emplace( std::forward<Us>(us)... );
}
};
template<typename T>
out_param<T> out( T& t ) { return out_param<T>(t); }
或类似上述的东西。
你现在得到如下语法:
void do_stuff( int x, in_param<expensive> y, io_param<something> z, out_param<double> d );
int main() {
expensive a;
something b;
double d;
do_stuff( 7, in(a), io(b), out(d) );
}
调用失败in
,io
或out
在调用站点失败会导致编译时错误。此外,在函数out_param
中意外读取out
变量的状态变得非常困难,从而在调用站点生成了一些非常好的文档。