阻止用户创建类的未命名实例

Vit*_*meo 18 c++ raii c++17

对于许多RAII"守卫"类,被实例化为匿名变量根本没有意义:

{
    std::lock_guard<std::mutex>{some_mutex};
    // Does not protect the scope!
    // The unnamed instance is immediately destroyed.
}
Run Code Online (Sandbox Code Playgroud)

{
    scope_guard{[]{ cleanup(); }};
    // `cleanup()` is executed immediately!
    // The unnamed instance is immediately destroyed.
}
Run Code Online (Sandbox Code Playgroud)

这篇文章:

C++中的匿名变量具有"表达式范围",这意味着它们在创建它们的表达式的末尾被销毁.


有没有办法阻止用户在没有名字的情况下实例化它们? ("预防"可能过于强烈 - "使其非常困​​难"也是可以接受的).

我可以想到两种可能的解决方法,但是它们在使用类时引入了语法开销:

  1. detail命名空间中隐藏类并提供宏.

    namespace detail
    {
        class my_guard { /* ... */ };
    };
    
    #define SOME_LIB_MY_GUARD(...) \
        detail::my_guard MY_GUARD_UNIQUE_NAME(__LINE__) {__VA_ARGS__}
    
    Run Code Online (Sandbox Code Playgroud)

    这是有效的,但是是hackish.

  2. 只允许用户通过高阶函数使用警卫.

    template <typename TArgTuple, typename TF>
    decltype(auto) with_guard(TArgTuple&& guardCtorArgs, TF&& f)
    {
        make_from_tuple<detail::my_guard>(std::forward<TArgTuple>(guardCtorArgs));
        f();
    }
    
    Run Code Online (Sandbox Code Playgroud)

    用法:

    with_guard(std::forward_as_tuple(some_mutex), [&]
    {
        // ...
    });
    
    Run Code Online (Sandbox Code Playgroud)

    当防护类的初始化具有"流畅"语法时,此解决方法不起作用:

    {
        auto _ = guard_creator()
                     .some_setting(1)
                     .some_setting(2)
                     .create();
    }
    
    Run Code Online (Sandbox Code Playgroud)

还有更好的选择吗?我可以访问C++ 17的功能.

Dav*_*aim 5

我想到的唯一合理的方法是让用户将结果传递guard_creator::create给一些guard_activator以左值引用作为参数的结果.

这样,类的用户无法创建具有名称的对象(大多数开发人员将要做的理智选项),或者new然后取消引用(疯狂选项)

例如,您在评论中说过您在非分配异步链创建器上工作.我可以考虑一个看起来像这样的API:

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 
Run Code Online (Sandbox Code Playgroud)

  • MSVC++发送了她的问候 (3认同)