Ora*_*lar 2 c++ templates c++03 c++98
假设您有一个经常重复的常见工作流程,但有一些变化:
我正在尝试实现一种机制,可以自动执行任意操作(在C++ 98中).例如,以下内容:
myMutex.acquire();
int a = foo(arg1, arg2, arg3);
myMutex.release();
return a;
Run Code Online (Sandbox Code Playgroud)
可能成为:
return doMutexProtected(myMutex, foo, arg1, arg2, arg3);
Run Code Online (Sandbox Code Playgroud)
或者一些类似的机制.挑战在于如何为任意类型a和任意类型和数量的参数执行此操作.
我有一种感觉,应该有一种方法来使用模板,但我不知道如何实现它.你可以用仿函数做类似的事情,但你必须提前告诉仿函数他们的参数类型 - 我希望有一种方法可以从被调用的原始函数中自动检测它们.这样,如果(当)函数的参数列表发生变化时,除了要调用的参数列表之外,您不必更新任何内容.
这可能吗?
在现代C++(C++ 17)中,函数看起来像
template <typename Mutex, typename Func, typename... Args>
decltype(auto) doMutexProtected(Mutex& mutex, Func&& func, Args&&... args)
{
std::unique_lock lg(mutex);
return std::forward<Func>(func)(std::forward<Args>(args)...);
}
Run Code Online (Sandbox Code Playgroud)
这会将互斥锁锁定为RAII类型,因此所有退出路径都会释放互斥锁,然后完美地转发该函数,并返回返回精确类型func返回的参数.
现在,由于你不能使用现代C++,我们必须尝试尽可能多地实现上述功能,并且有几种方法可以解决问题.实施std::unique_lock非常简单.根据您想要的功能,它可以如此简单
template <typename Mutex>
class my_unique_lock
{
public:
unique_lock(Mutex& mutex) : mutex(mutex) { mutex.lock(); }
~unique_lock() { mutex.unlock(); }
private:
Mutex& mutex;
unique_lock(unique_lock const&); // make it non copyable
};
Run Code Online (Sandbox Code Playgroud)
所以覆盖25%的问题:).不幸的是,这是最简单的部分.由于C++ 98/03没有decltype(auto),甚至decltype或者auto,我们需要提出一种不同的方式来获得返回类型.我们可以创建void并使用输出参数,这意味着您在调用函数时不需要指定任何内容,但这意味着您无法获得对返回内容的引用.以必须指定您想要的返回类型为代价,您可以使用类似的功能
template <typename Ret, typename Mutex, typename Func, typename Arg1>
Ret doMutexProtected(Mutex& mutex, Func func, Arg1 arg1)
{
my_unique_lock<Mutex> lg(mutex);
return func(arg1);
}
Run Code Online (Sandbox Code Playgroud)
你会称之为
T foo = doMutexProtected<T>(mutex, func, arg);
T& bar = doMutexProtected<T&>(mutex, func, arg);
Run Code Online (Sandbox Code Playgroud)
由于C++ 98/03没有可变参数模板,因此必须为不同数量的参数添加一堆重载,并且您必须确定哪个足够的参数就足够了,即:
template <typename Ret, typename Mutex, typename Func, typename Arg1>
Ret doMutexProtected(Mutex& mutex, Func func, Arg1 arg1) {...}
template <typename Ret, typename Mutex, typename Func, typename Arg1, typename Arg2>
Ret doMutexProtected(Mutex& mutex, Func func, Arg1 arg1, Arg2 arg2) {...}
template <typename Ret, typename Mutex, typename Func, typename Arg1, typename Arg2, typename Arg3>
Ret doMutexProtected(Mutex& mutex, Func func, Arg1 arg1, Arg2 arg2, Arg3 arg3) {...}
...
Run Code Online (Sandbox Code Playgroud)
然后你必须处理参考.现代版本完美地转发了所有内容(没有任何内容被复制,除非这是必需的Func).我们不能在C++ 98/03中这样做,所以我们必须添加所有的引用排列,所以我们不像第一个版本那样制作不必要的副本.这意味着
template <typename Ret, typename Mutex, typename Func, typename Arg1>
Ret doMutexProtected(Mutex& mutex, Func func, Arg1 arg1)
Run Code Online (Sandbox Code Playgroud)
实际上需要
template <typename Ret, typename Mutex, typename Func, typename Arg1>
Ret doMutexProtected(Mutex& mutex, Func& func, Arg1& arg1) {...}
template <typename Ret, typename Mutex, typename Func, typename Arg1>
Ret doMutexProtected(Mutex& mutex, Func const& func, Arg1& arg1) {...}
template <typename Ret, typename Mutex, typename Func, typename Arg1>
Ret doMutexProtected(Mutex& mutex, Func& func, Arg1 const& arg1) {...}
template <typename Ret, typename Mutex, typename Func, typename Arg1>
Ret doMutexProtected(Mutex& mutex, Func conts& func, Arg1 const& arg1) {...}
Run Code Online (Sandbox Code Playgroud)
当你添加更多参数时,这会变得气球.
如果您不想自己完成所有这些,我相信Boost至少已经完成了C++ 03的一些工作,您可以使用它们的实用程序.