EDIT:Подход, о котором говорится в вопросе, проблематичен по нескольким причинам. В конце концов я решил это, идя по-другому, см. Мой ответ ниже.Проверка типов шаблонов шаблонов
У меня есть несколько классов шаблонов, где ожидается, что параметр шаблона будет соответствовать определенному сигнатуру. Если пользователь поставляет аргумент шаблона, который либо не является вызываемым, либо не соответствует ожидаемой сигнатуре, тогда компиляция выходит из строя внутри механизма обратного вызова, и возникающие в результате сообщения об ошибках очень трудно расшифровать. Вместо этого я хотел бы использовать 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()
является вместо этого.
Это, кажется, работает для простых функций и определяемых пользователем функторов, но по некоторым причинам я не могу понять, она не для лямбды (протестировано с Clang 3.4 и г ++ 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");
}
Мое понимание что стандарт требует, чтобы лямбда были реализованы как анонимные функторы, эквивалентные g
выше, поэтому я не могу понять, почему первое работает, но последнее не работает.
Итак, в общем, мои вопросы:
- ли подход, который я использовал здесь на самом деле разумно, или я сделал очевидную ошибку?
- Почему это, похоже, работает для определяемых пользователем функторов, но не для компилятора (например, lambdas)?
- Есть ли исправление/обходное решение, чтобы лямбды можно было проверить таким образом?
- Есть ли еще какие-либо улучшения, которые я мог бы внести в этот код? (Возможно, много ...)
Заранее благодарим за это, это подталкивает рамки моих знаний метапрограммирования шаблона, поэтому любые советы будут с благодарностью получены.
Код с [этого ответа] (http://stackoverflow.com/a/12283159/3920237), похоже, работает. [Живой пример] (http://coliru.stacked-crooked.com/a/f951bb2b4ca90efd) – 2014-09-01 11:02:41