防止用户创建类的未命名实例 [英] Preventing users from creating unnamed instances of a class
问题描述
对于许多 RAII后卫 类,将其实例化为匿名变量根本没有任何意义:
For many RAII "guard" classes, being instantiated as anonymous variables does not make sense at all:
{
std::lock_guard<std::mutex>{some_mutex};
// Does not protect the scope!
// The unnamed instance is immediately destroyed.
}
{
scope_guard{[]{ cleanup(); }};
// `cleanup()` is executed immediately!
// The unnamed instance is immediately destroyed.
}
来自这篇文章:
C ++中的匿名变量具有表达式范围,这意味着它们将在创建它们的表达式的末尾销毁。
Anonymous variables in C++ have "expression scope", meaning they are destroyed at the end of the expression in which they are created.
有什么方法可以防止用户实例化它们而没有名称吗? (预防可能太强大了-很难也是可以接受的。)
我可以想到两种可能的解决方法,但是它们在使用该类时引入了语法开销:
I can think of two possible workarounds, but they introduce syntactical overhead in the use of the class:
-
将类隐藏在
详细信息
命名空间中,并提供一个宏。
Hide the class in a
detail
namespace and provide a macro.
namespace detail
{
class my_guard { /* ... */ };
};
#define SOME_LIB_MY_GUARD(...) \
detail::my_guard MY_GUARD_UNIQUE_NAME(__LINE__) {__VA_ARGS__}
这是有效的,但 hackish 。
仅允许用户通过高阶函数使用防护装置。
Only allow the user to use the guard through an higher-order function.
template <typename TArgTuple, typename TF>
decltype(auto) with_guard(TArgTuple&& guardCtorArgs, TF&& f)
{
make_from_tuple<detail::my_guard>(std::forward<TArgTuple>(guardCtorArgs));
f();
}
用法:
with_guard(std::forward_as_tuple(some_mutex), [&]
{
// ...
});
当防护类的初始化具有流利语法时,此解决方法不起作用:
This workaround does not work when the initialization of the guard class has "fluent" syntax:
{
auto _ = guard_creator()
.some_setting(1)
.some_setting(2)
.create();
}
有没有更好的选择替代?我可以使用C ++ 17功能。
Is there any better alternative? I have access to C++17 features.
推荐答案
我想到的唯一明智的方法是让用户通过结果 guard_creator :: create
到某些 guard_activator
的过程,该过程以左值引用作为参数。
The only sensible way I think about is to make the user pass the result of guard_creator::create
to some guard_activator
which takes a lvalue-reference as a parameter.
这样,类的用户只能用名称(大多数开发人员会使用的明智选项)创建对象,或者使用 new
然后取消引用(疯狂的选择)
this way, the user of the class has no way but either create the object with a name (the sane option that most developers will do), or new
it then dereference (insane options)
例如,您在注释中说,您正在使用非分配异步链创建器。我可以考虑使用如下所示的API:
for example, you said in the comments you work on a non allocating asynchronous chain creator. I can think on an API which looks like this:
auto token = monad_creator().then([]{...}).then([]{...}).then([]{...}).create();
launch_async_monad(token); //gets token as Token&, the user has no way BUT create this object with a name
这篇关于防止用户创建类的未命名实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!