是否可以访问另一个函数中定义的自动静态变量的* type *?

时间:2012-09-03 16:09:54

标签: c++ lambda c++11

(这里的根本问题是我试图在涉及lambdas的复杂表达式上使用decltype或其他类型的推论(可能基于auto。我试图找到一些解决方法。我一直在玩http://pfultz2.github.com/Pythy/多态lambda。我不能完全没有告诉你长篇故事的动机!)

我希望能够decltype([](int){return 3.5L};获取lambda的类型,或者至少返回类型。是的,我知道lambdas被赋予了一种独特的类型,我不需要提醒decltype([](int){return 3.5L};如果在两个不同的行上使用,它将提供两种不同的类型。

如果我在lambda上使用decltype,那么我会收到一条错误消息('lambda在未评估的上下文中使用')。我知道这似乎是一个合理的错误信息,但我很惊讶C ++握着那样的手!允许这样做是有用的,特别是访问lambda的返回类型。这个错误只是过度出错的错误消息的结果,还是真的有一个很好的理由说明为什么不能这样做呢?

这样的表达式在成员函数中起作用:

template<typename T>
struct X {
    void foo() {
        static auto l = [](int){return 3.5;};
    }
};

但我不允许这样做:

template<typename T>
struct X {
    static auto var = [](int){return 3.5;}; // will also fail if I use constexpr here
};

x.cpp:8:47: error: expression ‘#‘lambda_expr’ not supported by
    dump_expr#<expression error>’ is not a constant-expression
x.cpp:8:47: error: unable to deduce ‘const auto’ from ‘<expression error>’

这激发了我的想法,试图在函数中使用静态变量,以便对lambda进行类型推断。

如果X不是模板,这看起来好一点。但我需要X作为模板 - 特别是lambda的参数将采用模板参数的类型。

请记住,我只想要lambda的类型,我只对返回类型感到满意。令人沮丧的是编译器愿意并且能够在两种情况下进行类型推断和静态初始化,但它似乎在我的方式中设置了一些任意障碍。

我可以从var_in_func函数外部访问变量dummy_func类型吗?

struct S {
    constexpr static auto member = a_complicated_expression...  // error
    void dummy_func() {
        static auto var_in_func = a_complicated_expression...    // OK
    }
    typedef dummy_func :: var_in_func the_type; // I'd like this to work
};

如果a_complicated_expression...中有lambda,则member的初始化程序通常会出现问题。如果S实际上是一个结构模板,那么我会收到member没有初始化程序的错误消息。这就是我试图找到其他方法的原因。

但是,静态方法static auto中的dummy_func变量可以正常工作。这让我觉得他们应该是一种访问静态变量类型的好方法吗?

我尝试了以下但是它没有用,因为dummy_func不是一种类型(足够公平):

typedef dummy_fun :: var_in_func the_type_of_the_static_variable_in_the_method;

我无法做decltype( a_complicated_expression... )因为编译器抱怨在未评估的上下文中使用lambda(一个declspec)。

我正在使用g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3。我不介意我是否必须使用g ++特定扩展。

2 个答案:

答案 0 :(得分:1)

非捕获lambda可以转换为函数指针,并且operator()具有该函数指针的签名:

template<typename C, typename R, typename... Args>
auto remove_class(R (C::*)(Args...)) -> R(*)(Args...);
template<typename C, typename R, typename... Args>
auto remove_class(R (C::*)(Args...) const) -> R(*)(Args...);
template<typename C, typename R, typename... Args>
auto remove_class(R (C::*)(Args...) volatile) -> R(*)(Args...);
template<typename C, typename R, typename... Args>
auto remove_class(R (C::*)(Args...) const volatile) -> R(*)(Args...);

template<typename T>
auto to_f_ptr(T t) -> decltype(remove_class(&T::operator())) { return t; }

您现在可以写auto var = to_f_ptr([](int){return 3.5;});var会有double (*)(int)类型。

但是,您仍然无法将lambda用作类范围static初始化程序;见lambda as a static member

答案 1 :(得分:0)

lambda函数仅在其范围的上下文中定义。这意味着静态成员函数中的lambda函数与其他地方定义的不同类型。在我看来,获得lambda函数的返回类型超出其范围是不明智的,不应该是可能的。

必须有另一种方式(不涉及lambda)才能获得所需的类型,因为在任何潜在的lambda函数范围之外定义这样的类型显然是有意义的。