Lambda 函数调用函数模板参数的静态函数失败

Posted

技术标签:

【中文标题】Lambda 函数调用函数模板参数的静态函数失败【英文标题】:Lambda function failing to call static functions of a function template parameter 【发布时间】:2011-12-28 03:01:34 【问题描述】:

好的,所以我的设置基本上是这样的:

template<typename T> void example()

 std::function<int (byte*)> test = [=](byte* start) -> int
 
  return T::magic(start);
 

忽略这些裸调用是多么“不干净”,它也无法编译,并给出以下错误:

'T' : is not a class or namespace name
'magic': identifier not found

有什么方法可以调用泛型类型名 T,假设我将始终使用具有函数 magic(byte* start) 的类调用 example()?当然,我不必为将要执行此操作的每个类重新声明此模板函数。

我在 VC++ 2010 中执行此操作,看来它可能是编译器错误。任何可能的解决方法?

【问题讨论】:

这是什么编译器? AFAIK,它应该可以工作。 @ArunMu,恐怕那会期望T::magic 是一个类型名。是的,上面的例子应该可以工作,除非在其他地方搞砸了。什么是编译器? 看起来您无法在 C++11 ***.com/questions/3575901/… 中模板化 lambda。但是,您可以改用宏。 @WTP :我确定迈克尔在问 OP,他使用的是哪个编译器 :) 如果 Michael 在不知道编译器是什么的情况下获得 14k,则堆栈溢出评分系统存在严重问题。 【参考方案1】:

唯一的错误是缺少分号。一旦修复,它就可以正常工作了。

#include <iostream>
#include <functional>

typedef unsigned char byte;

template<typename T> void example()

    std::function<int (byte*)> test = [=](byte* start) -> int
    
        return T::magic(start);
    ; // <--------------------------------- You were missing that


struct Foo 
    static int magic(byte*);
;

int Foo::magic(byte* start)

    std::cout << "magic\n";


int main()

    example<Foo>();

http://ideone.com/dRdpI

由于这似乎是 VC10 的 lambda 实现中的一个错误,一个可能的解决方法是创建一个本地仿函数类:

template<typename T> void example()

    struct Foo 
        int operator()(byte * start)  return T::magic(start); 
    ;

    std::function<int (byte*)> test = Foo();    

【讨论】:

分号和非标准的byte typename 是的,对不起,我很快就写好了这个例子,没有检查。我的实际代码中有分号和字节 typedef。我不确定这里出了什么问题。我是用VC++ 2010编译的,你用的是什么? @user173342:我使用的是 GCC 4.5。但是我刚刚在VC10中测试过,现在我看到了你的错误。看起来像一个编译器错误。 好的,谢谢,感谢您对我的代码有效的健全性检查,我在其他地方找到了解决方案。基本上,在 lambda 之前为静态函数设置一个 auto 变量可以让 lambda 捕获该 auto 变量并通过它进行调用。 @user173342:请您发布那个作为答案吗?我浪费时间试图找到几乎那个解决方案,而接受的答案并没有你的解决方法那么有用......【参考方案2】:

我用 VS2010 重现了这个问题。你需要调用example函数,但是:

#include <functional>

struct SomeT  static int magic(unsigned char*)  return 42;  ;

template<typename T> void example()

    std::function<int (unsigned char*)> test = [=](unsigned char* start) -> int
    
        return T::magic(start);
    ;


int main()

    example<SomeT>();

更新基于 OP 的评论:

这行得通:

#include "stdafx.h"
#include <functional>

struct SomeT  static int magic(unsigned char*)  return 42;  ;

template<typename T> void example()

    auto func = T::magic;
    std::function<int (unsigned char*)> test = [=](unsigned char* start) -> int
    
        return func(start);
    ;


int main()

    example<SomeT>();

我一直在寻找解决方法,但还没有一个可行的方法,我尝试了并包含这个不错的排列,但还没有运气:

template<typename T> void example()

    static const T* workaround;
    std::function<int (unsigned char*)> test = [=](unsigned char* start) -> int
    
        typedef decltype(*workaround) innerT;
        return innerT::magic(start);
    ;

这很难...

【讨论】:

不需要创建T 类型的对象。我认为 OP 的意思是他做了auto x = T::magic;,然后在 lambda 内部,他调用了x(start); 是的,它是一个静态函数。您希望将 auto 变量设置为实际函数本身,而不是类。该类永远不会被实例化。 @BenjaminLindley:好主意,我没想到函数类型。经过测试和修复的答案 您看,@user173342:这正是发布该解决方法很有帮助的原因,因为人们可能会绕着圈子讨论如何使用非公开可构造的类型来解决这个问题。 尝试了两次 :)【参考方案3】:

我确定你做错了什么,因为我可以在 lambda 中使用语法 T::f() 调用静态方法:

#include <iostream>
#include <functional>
struct A

   static void f()  std::cout << "called" << std::endl; 
;

template<typename T> 
void example()

  std::function<void()> test = [=]()  T::f(); ;
  test();

int main() 
        example<A>();
        return 0;


演示:http://ideone.com/IPakS

所以请发布更多信息。直到这是答案。尝试将您的代码与此进行比较,看看您是否做错了什么。

如果您使用的是 GCC,您是否使用 -std=c++11 选项编译代码?

【讨论】:

以上是关于Lambda 函数调用函数模板参数的静态函数失败的主要内容,如果未能解决你的问题,请参考以下文章

无法通过自定义 cloudformation 资源调用 lambda 函数

Lambda 函数作为基类

泛函编程—模板函数_类模板

将 lambda 作为模板参数传递给函数指针函数模板化

将 lambda 作为参数传递 - 通过引用或值?

在Lambda函数中查找请求的URL