开发者

Template specialization for passing a lambda

开发者 https://www.devze.com 2023-03-25 04:17 出处:网络
I am stuck on specializing a template function for a lambda : class X { public: template <typename T>

I am stuck on specializing a template function for a lambda :

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::e开发者_高级运维ndl; }); // should print "lambda"

Casting the lambda to a std::function before passing to f and specializing for this type works, but is tedious to write. Is there a solution in C++0x?

Edit: I am totally fine with a solution, which would enable me to specialize for a callable if the last line of passing a lambda works.


The following is a variation of the good old sizeof trick. Maybe it can be done with decltype alone. It does not exactly check if its a lambda, but if it is callable. If you want to filter out other callable things, you can use C++0x type traits to check if they are functions, member functions, composit objects etc.

#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"
}


you cannot do this directly: the type of the lambda is created by the compiler and is different for each lambda. You can specialize for it, but it would be for that type only (see example below). You can remove some of the tediousness though by using a small function for converting lambda -> 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!
0

精彩评论

暂无评论...
验证码 换一张
取 消