您可以使用 SFINAE 和一些特征类来做到这一点。
我怀疑最好的方法是期待一个调用兼容的函子——这也更容易。
#include <utility>
#include <type_traits>
template<typename T, bool=true>
struct raw_write_compatible: std::false_type {};
template<typename T, bool=true>
struct raw_read_compatible: std::false_type {};
template<typename T>
struct raw_write_compatible<
T,
std::is_convertable<
decltype(
std::declval<T&>()(
std::declval<uint8_t *>(),
std::declval<size_t>()
)
),
int
>::value
>: std::true_type {};
template<typename T>
struct raw_read_compatible<
T,
std::is_convertable<
decltype(
std::declval<T&>()(
std::declval<uint8_t *>(),
std::declval<size_t>()
)
),
int
>::value
>: std::true_type {};
这些的要点是,raw_read_compatible< T >::value
如果true
的实例T
可以通过签名评估(uint8_t*, size_t)
,并且返回类型可以转换为int
。
(顺便说一句,您的“写入”函数签名可能应该采用指向 的指针const uint8_t
,因为它不会修改该参数。)
你会像这样使用它:
template<typename Reader, typename Writer>
typename std::enable_if<
raw_read_compatible<Reader>::value && raw_write_compatible<Writer>::value,
bool // return value of do_some_io_stuff
>::type do_some_io_stuff( Reader const& reader, Writer const& writer ) {
return true;
}
do_some_io_stuff
如果可以以您想要的方式调用读取器/写入器,它将匹配。
这样做的好处是当您尝试传入不兼容的 lambda 或函数指针或仿函数时do_some_io_stuff
无法匹配,而不是匹配然后无法编译。从理论上讲,这可以让您覆盖事物。
上述解决方案需要具有良好 C++11 支持的编译器:例如,MSVC2012 不适用于上述解决方案(它缺少“表达式 SFINAE”)。
一个更简单的解决方案是只采用 a std::function< int(uint8_t*, size_t) >
,但这有两个成本:首先,它在每次调用时都有运行时间成本(大致相当于一个virtual
方法调用——因此与 io 相比并不那么高)——真正的成本在函数调用边界上进行阻塞优化。其次,根据我的经验,您可能会遇到一些编译失败而不是无法匹配签名错误(我不确定 C++11 标准是否已指定std::function
' 的“lambda”构造函数仅在传递兼容类型时才应匹配,但我想我已经看到了未通过该测试的实现)。
该std::function
解决方案的优点是它更简单,它允许将实现放在单独的文件中,并且意图更容易理解。