Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to access the *type* of an auto static variable that's defined in another function?

Tags:

c++

c++11

lambda

(The root problem here is that I'm trying to use decltype, or some other type deduction perhaps based on auto, on complicated expressions that involve lambdas. I'm trying to find some sort of workaround. I've been playing around with http://pfultz2.github.com/Pythy/ for polymorphic lambdas. I can't fully go into the motivation without telling you all a long story! )

I want to be able to do decltype([](int){return 3.5L}; to get the type of the lambda, or at least the return type. Yes, I know that lambdas are given a unique type, I don't need to be reminded that decltype([](int){return 3.5L}; will give two different types if used on two different lines.

If I use decltype on a lambda, then I get an error message ('lambda used in unevaluated context'). I know that seems like a reasonable error message, but I'm surprised at C++ holding my hand like that! It would be useful to be allowed to do this, in particular to access the return type of the lambda. Is this error simply a result of overzealous error messages, or is there truly a good reason why it can't be done?

An expression such as this works inside a member function:

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

but I'm not allowed to do:

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>’

This inspired my idea to try to use a static variable in a function in order to do the type inference on the lambda.

This seems to work a little better if X is not a template. But I need X to be a template - in particular, the arguments to the lambda will take the type of the template parameters.

Remember, I only want the type of the lambda, and I would be satisfied only with the return type. It's frustrating that the compiler is willing and able to do type inference, and static initialization, in both cases, but it seems to put some arbitrary obstacles in my way.

Can I access the type of the variable var_in_func from outside the dummy_func function?

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
};

If there are lambdas in a_complicated_expression..., there is often a problem with the initializer for member. If S is actually a struct template, then I get error messages that member has no initializer. That's why I'm trying to find other ways around this.

However, the static auto variable inside the static method dummy_func works fine. So that got me thinking that they ought to be a nice way to access the type of that static variable?

I tried the following but it didn't work because dummy_func isn't a type (fair enough):

typedef dummy_fun :: var_in_func the_type_of_the_static_variable_in_the_method;

I can't do decltype( a_complicated_expression... ) as the compiler complains about the use of a lambda in an unevaluated context (a declspec).

I'm using g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3. I don't mind if I have to use g++ specific extensions.

like image 977
Aaron McDaid Avatar asked Sep 03 '12 16:09

Aaron McDaid


People also ask

Can static variables be accessed by other functions?

If a static variable is defined outside of the functions it will be accessible only by the code that follows in the file it is declared. If the static variable is declared in a function, it will only be accessible from the function, and it will keep its value between function executions.

Can you access a static variable?

Static variables can be accessed by calling with the class name ClassName. VariableName. When declaring class variables as public static final, then variable names (constants) are all in upper case. If the static variables are not public and final, the naming syntax is the same as instance and local variables.

Can static variable accessed anywhere?

So, the benefit of using a static variable as a global variable is that it can be accessed from anywhere inside the program since it is declared globally. Below is the code which shows how it is declared.

How do you access a variable in a static method?

By using static variables a single copy is shared among all the instances of the class, and they can be accessed directly by class name and don't require any instance. The Static method similarly belongs to the class and not the instance and it can access only static variables but not non-static variables.


1 Answers

Non-capturing lambdas can be converted to a function pointer, and have an operator() with the signature of that function pointer:

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; }

You can now write auto var = to_f_ptr([](int){return 3.5;}); and var will have type double (*)(int).

However, you still won't be able to use the lambda as a class-scope static initialiser; see lambda as a static member.

like image 173
ecatmur Avatar answered Oct 03 '22 17:10

ecatmur