【问题标题】:How can I use decltype on a variable in a lambda without capturing it?如何在 lambda 中的变量上使用 decltype 而不捕获它?
【发布时间】:2016-09-13 22:01:47
【问题描述】:

我正在尝试设计一个需要如下所示的 C++ 宏:

#define MY_MACRO(OBJECT, METHOD)                            \
    [](BaseClass* obj)                                      \
    {                                                       \
        return static_cast<decltype(OBJECT)>(obj)->METHOD();\
    }

基本上,一个宏转换为 lambda,它调用给定对象的给定方法。但是 lambda 需要将对象的基类作为参数(我的用例保证强制转换始终有效)。此外,要调用的方法可能不在基类上。

这个宏的用法是我有另一个我不能修改的方法声明为:

void Foo(std::function<int(BaseClass*)>);

并且我需要能够使用我的宏作为参数来调用它,如下所示:

T x;
Foo(MY_MACRO(x, method));  // match std::function<int(T*)>

但是,宏代码不起作用,因为我没有捕获 OBJECT,所以当我需要将它传递给 decltype 时,它​​不在范围内。但从概念上讲,编译器需要的所有信息都在那里......我该怎么做?有可能吗?

一些限制:

  1. lambda 的参数需要是 BaseClass。我不能让它 decltype(OBJECT)。
  2. 我的情况不允许我捕获 OBJECT。
  3. 我无权访问通用 lambda 捕获的 C++14 功能。

【问题讨论】:

  • 你考虑过std::mem_fn吗?
  • 是的,我已经尝试过了,但我无法在我的情况下使用它。我正在概括我的问题陈述;事实上,事情并没有这么简单。但最重要的是它必须是一个 lambda,我需要访问对象的类型而不捕获它。
  • 你能添加一个使用例子吗,只是为了说明?
  • 已添加到问题中。
  • 有问题的用法示例是实际传递给宏的内容。

标签: c++ lambda decltype


【解决方案1】:

我需要访问对象的类型而不捕获它。

你可以直接做。仅当您 odr-使用命名实体时才需要捕获,并且未计算的操作数(如 decltype 的操作数)不使用任何其他操作数。这很好:

void f(){
    int x; 
    []{ decltype(x) y = 0; };
}

【讨论】:

  • 有趣,这在 Visual Studio 中编译失败。编译器错误?
  • @PaulAccisano MSVC,嗯? /叹息
【解决方案2】:

您可以为 lambda 添加所需类型的可选参数,并在该参数上使用 decltype。这是模式的示例,减去宏:

int main() {
    int foo = 4;
    auto lambda = [](double* bar, decltype(foo)* TP = nullptr) {
        return static_cast<std::remove_pointer<decltype(TP)>::type>(*bar);
    };

    double x = 5;
    return lambda(&x);
}

我在这里得到一个指向decltype(foo) 的指针,因为指针类型可以很容易地默认为nullptr 以确保参数是可选的。如果decltype(foo) 已经解析为指针类型,就像你的情况一样,如果我做对了,你就不需要它(和remove_pointer)。

【讨论】:

  • 很遗憾,我不能这样做,因为我需要宏来评​​估与 std::function 匹配的东西。不用担心 int,我的用例保证类型总是匹配的。
  • @PaulAccisano,您可以通过在另一个具有正确签名的 lambda 中捕获该 lambda 来逃脱。
  • @PaulAccisano,不,等等,你甚至不需要那个。 lambda 可以直接进入该类型的 std::functioncppshell.com/2uy5x
  • 哇!我不知道 std::function 这么灵活!惊人的!我认为这是要走的路。
  • 工作如梦!谢谢!
【解决方案3】:

这是一个尝试:

template <typename T>
auto lambda_maker(int (T::* MF)())
{
    return [](T* p) -> int { return (p->*MF)(); };
}

#define MY_MACRO(OBJ, METH) lambda_maker<decltype(OBJ)>(METH)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-25
    • 2020-11-07
    • 1970-01-01
    • 2020-05-29
    相关资源
    最近更新 更多