Шаблон специализации для прохождения лямбды - PullRequest
2 голосов
/ 03 августа 2011

Я застрял на том, чтобы специализировать функцию шаблона для лямбды:

class X
{
  public:
    template <typename T>
    void f(T t) 
    { 
      std::cout << "awesome" << std::endl; 
    };

    template <>
    void f(double t) 
    {
      std::cout << "trouble" << std::endl; // Works
    }

    template <>
    void f(??? t) // what to put here?
    {
      std::cout << "lambda" << std::endl;
    }  
};


X x;
x.f(42); // prints "awesome"
x.f(1.12); // prints "trouble"
x.f([](){ std::cout << "my lazy lambda" << std::endl; }); // should print "lambda"

Приведение лямбды к std :: function перед передачей в f и специализация для этого типа работает, но писать утомительно.Есть ли решение в C ++ 0x?

Редактировать: я полностью согласен с решением, которое позволило бы мне специализироваться на вызываемом вызове, если работает последняя строка прохождения лямбды.

Ответы [ 2 ]

4 голосов
/ 03 августа 2011

Ниже приведен вариант старого доброго размера трюка.Может быть, это можно сделать только с помощью decltype.Он точно не проверяет, является ли это лямбда, но может ли он быть вызван.Если вы хотите отфильтровать другие вызываемые объекты, вы можете использовать признаки типа C ++ 0x, чтобы проверить, являются ли они функциями, функциями-членами, составными объектами и т. Д.

#include <functional>
#include <iostream>
#include <type_traits>

template<class T>
char is_callable( const T& t, decltype( t())* = 0 );

long is_callable( ... );

class X
{
  public:
    template <typename T>
    void f( const T& t, typename std::enable_if<sizeof(is_callable(t)) !=1>::type* = 0 )
    {
      std::cout << "awesome" << std::endl;
    };

    void f(double )
    {
      std::cout << "trouble" << std::endl; // Works
    }

    template<class T>
    void f( const T& t, typename std::enable_if<sizeof(is_callable(t)) == 1>::type* = 0 )
    {
      std::cout << "lambda" << std::endl;
    }
};

int main(int argc, const char *argv[])
{
    X x;
    x.f(42); // prints "awesome"
    x.f(1.12); // prints "trouble"
    x.f([](){ std::cout << "my lazy lambda" << std::endl; }); // should print "lambda"
}
1 голос
/ 03 августа 2011

вы не можете сделать это напрямую: тип лямбды создается компилятором и отличается для каждой лямбды. Вы можете специализироваться на этом, но это будет только для этого типа (см. Пример ниже). Вы можете удалить некоторые утомительные вещи, используя небольшую функцию для преобразования лямбда -> std :: function.

auto myLambda = [](){ std::cout << "myLambda" << std::endl; };

class X
{
  public:
    template <typename T>
    void f( T t )
    { 
      std::cout << "not so awesome" << std::endl; 
    };

    void f( const std::function< void() >& f )
    {
      std::cout << "function" << std::endl;
    }

    void f( const decltype( myLambda )& f )
    {
      std::cout << "myLambda" << std::endl;
    }
};

  //helper for lambda -> function
template< class T >
std::function< void() > Function( const T& f )
{
  return std::function< void() >( f );
}

X x;
x.f( myLambda ); //prints "myLambda"
x.f( Function( [](){ std::cout << "blah" << std::endl; } ) ); //prints "function"
x.f( [](){ std::cout << "blah" << std::endl; } ); //still won't work: not the same type as myLambda!
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...