【问题标题】:Template specialization for passing a lambda用于传递 lambda 的模板特化
【发布时间】:2011-08-03 14:12:28
【问题描述】:

我一直坚持为 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::endl; }); // should print "lambda"

在传递给 f 并专门针对这种类型之前将 lambda 转换为 std::function 是可行的,但编写起来很乏味。 C++0x有解决办法吗?

编辑:我完全可以接受一个解决方案,如果传递 lambda 的最后一行有效,这将使我能够专注于可调用对象。

【问题讨论】:

标签: templates lambda c++11 template-specialization


【解决方案1】:

以下是旧的 sizeof 技巧的变体。也许可以单独使用 decltype 来完成。它不完全检查它是否为 lambda,但它是否可调用。如果你想过滤掉其他可调用的东西,你可以使用 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"
}

【讨论】:

  • 这不会专门用于 lambda,只有可调用类型 - 不一样。
  • 这可能是最好的,也许只是改变 sfinae 来测试准确的签名,而不是所有可调用的类型
  • @DeadMG:只要我能避免最后的演员表,我完全可以匹配任何可调用对象。
【解决方案2】:

您不能直接这样做:lambda 的类型是由编译器创建的,并且对于每个 lambda 都是不同的。您可以专门针对它,但它仅适用于该类型(请参见下面的示例)。你可以通过使用一个小函数来转换 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!

【讨论】:

  • 最后一行永远不会匹配 lambda,因为每个 lambda 都有不同的唯一类型
猜你喜欢
  • 2023-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多