Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lambda function failing to call static functions of a function template parameter

Ok, so I have something setup basically like this:

template<typename T> void example()
{
 std::function<int (byte*)> test = [=](byte* start) -> int
 {
  return T::magic(start);
 }
}

Ignoring how "unclean" making these naked calls is, it also doesn't compile, giving these errors:

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

Is there any way to be able to make a call on the generic typename T, assuming I will always be calling example() with a class that has the function magic(byte* start)? Surely I don't have to redeclare this template function for every single class that will be doing this.

I'm doing this in VC++ 2010, and it appears it may be a compiler bug. Any possible workarounds?

like image 531
user173342 Avatar asked Nov 13 '11 16:11

user173342


People also ask

Can lambda function be a template?

From the various lambda improvements, template parameters for lambdas are my favorite ones. Lambdas support with C++20 template parameters, can be default-constructed and support copy-assignment, when they have no state, and can be used in unevaluated contexts.

Are lambda functions static?

A lambda or anonymous method may have a static modifier. The static modifier indicates that the lambda or anonymous method is a static anonymous function. A static anonymous function cannot capture state from the enclosing scope.

How do you write a lambda function in C++?

Creating a Lambda Expression in C++auto greet = []() { // lambda function body }; Here, [] is called the lambda introducer which denotes the start of the lambda expression. () is called the parameter list which is similar to the () operator of a normal function.

How do you structure a lambda function?

Lambda functions can be divided into two parts: code inside the handler function and the code outside of it. Code outside the handler function only gets executed during the cold start, while the code inside the handler executes per each function call.


2 Answers

The only error there is the missing semi-colon. Once that is fixed, it works fine.

#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

As this appears to be a bug in VC10's lambda implementation, a possible workaround is to create a local functor class:

template<typename T> void example()
{
    struct Foo {
        int operator()(byte * start) { return T::magic(start); }
    };

    std::function<int (byte*)> test = Foo();    
}
like image 193
Benjamin Lindley Avatar answered Oct 06 '22 01:10

Benjamin Lindley


I reproduced the problem with VS2010. You need to call the example function, though:

#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>();
}

Update based on a comment by the OP:

This works:

#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>();
}

I have been looking for workarounds, but none working yet, I tried up to and including this nice permutation, but no luck yet:

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

Tough one this...

like image 41
sehe Avatar answered Oct 05 '22 23:10

sehe