編輯:由於幾個原因,問題中概述的方法存在問題。最後,我以不同的方式解決了這個問題,請參閱下面的答案。檢查可召回的模板參數類型
我有一些模板類,其中的模板參數預計是一個可調用匹配某個簽名。如果用戶提供的模板參數不是可調用的或者與預期的簽名不匹配,那麼編譯將在回調機制內部深陷失敗,並且產生的錯誤消息很難破譯。相反,如果給定的模板參數無效,我希望能夠使用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