编辑:由于几个原因,问题中概述的方法存在问题。最后,我以不同的方式解决了这个问题,请参阅下面的答案。检查可召回的模板参数类型
我有一些模板类,其中的模板参数预计是一个可调用匹配某个签名。如果用户提供的模板参数不是可调用的或者与预期的签名不匹配,那么编译将在回调机制内部深陷失败,并且产生的错误消息很难破译。相反,如果给定的模板参数无效,我希望能够使用static_assert
提供一个好的,易于理解的错误消息。不幸的是,这似乎很难做到。
我使用以下设置:
#include <type_traits>
namespace detail {
template <typename Function, typename Sig>
struct check_function
{
static constexpr bool value =
std::is_convertible<Function, typename std::decay<Sig>::type>::value;
};
template <typename, typename>
struct check_functor;
template <typename Functor, typename Ret, typename... Args>
struct check_functor<Functor, Ret(Args...)>
{
typedef Ret (Functor::*Memfn) (Args...);
static constexpr bool value =
check_function<decltype(&Functor::operator()), Memfn>::value;
};
} // end namespace detail
template <typename Func, typename Sig>
struct check_function_signature
{
using Type =
typename std::conditional<
std::is_function<Func>::value,
detail::check_function<Func, Sig>,
detail::check_functor<Func, Sig>>::type;
static constexpr bool value = Type::value;
};
即,如果Func
是一个函数指针类型,它直接相比所需的签名,否则其被假定为一个算符和其operator()
是相反。
这似乎是一些简单的功能和用户定义的函数子工作,但由于某种原因,我无法理解失败的lambda表达式(铿锵3.4测试和g ++ 4.8):
int f(int i);
struct g
{
int operator() (int i) { return i; }
};
int main()
{
static_assert(check_function_signature<decltype(f), int(int)>::value,
"Fine");
static_assert(check_function_signature<g, int(int)>::value,
"Also fine");
auto l = [](int i) { return i; };
static_assert(check_function_signature<decltype(l), int(int)>::value,
"Fails");
}
我的理解是该标准要求lambda类实现为等效于上面g
的匿名函子,所以我不明白为什么前者可行,但后者不行。
因此,总的来说,我的问题:
- 是我在这里用实际合理的做法,或已我做一个明显的错误?
- 为什么这似乎适用于用户定义的仿函数,但编译器定义的仿函数(即lambda表达式)失败?
- 是否有修复/解决方法,以便可以用这种方式检查lambda?
- 我可以对此代码进行其他改进吗? (可能很多...)
在此先感谢,这是推动我的模板元编程知识的限制,所以任何建议将感激地收到。
来自[此答案](http://stackoverflow.com/a/12283159/3920237)代码似乎工作。 [现场示例](http://coliru.stacked-crooked.com/a/f951bb2b4ca90efd) – 2014-09-01 11:02:41