0

I'm trying to use C++ lambdas for the first time.

My code looks like the following:

struct ImportModeInfo
{
    CImportTransactions::ImportMode Mode;
    LPCTSTR pszDisplayName;
    CImportTransactions *(*pFactory)(LPCTSTR pszDataFile, LPCTSTR pszCsvFile, LPCTSTR pszLogFile);
};

CImportTransactions::ImportModeInfo CImportTransactions::ImportModeTable[] =
{
    { CImportTransactions::ImportMode::GasBoy, _T("GasBoy"), [](LPCTSTR p1, LPCTSTR p2, LPCTSTR p3) { return new CImportGasBoyTransactions(p1, p2, p3); } },
    { CImportTransactions::ImportMode::Opw, _T("OPW/AFC"), [](LPCTSTR p1, LPCTSTR p2, LPCTSTR p3) { return new CImportOpwTransactions(p1, p2, p3); } },
};

As it is, Intellisense highlights the [ starting the capture list, giving me the following error:

more than one conversion function from "lambda []CImportGasBoyTransactions *(LPCTSTR p1, LPCTSTR p2, LPCTSTR p3)->CImportGasBoyTransactions *" to "<error-type>" applies:

function "CImportTransactions::lambda []CImportOpwTransactions *(LPCTSTR p1, LPCTSTR p2, LPCTSTR p3)->CImportOpwTransactions *::operator CImportOpwTransactions *(*)(LPCTSTR p1, LPCTSTR p2, LPCTSTR p3)() const"
function "CImportTransactions::lambda []CImportOpwTransactions *(LPCTSTR p1, LPCTSTR p2, LPCTSTR p3)->CImportOpwTransactions *::operator CImportOpwTransactions *(*)(LPCTSTR p1, LPCTSTR p2, LPCTSTR p3)() const"
function "CImportTransactions::lambda []CImportOpwTransactions *(LPCTSTR p1, LPCTSTR p2, LPCTSTR p3)->CImportOpwTransactions *::operator CImportOpwTransactions *(*)(LPCTSTR p1, LPCTSTR p2, LPCTSTR p3)() const"
function "CImportTransactions::lambda []CImportOpwTransactions *(LPCTSTR p1, LPCTSTR p2, LPCTSTR p3)->CImportOpwTransactions *::operator CImportOpwTransactions *(*)(LPCTSTR p1, LPCTSTR p2, LPCTSTR p3)() const"

I really don't understand what any of this means. I don't see that my lambda expressions are using any variables other than the three that are passed to them. It's true I allocate a new object, but again that is from inside the lambda.

If I change [] to [=] or [&], the error goes away. Can anyone explain why either of these changes would be needed in this case?

UPDATE: Actually, it looks like I still get the following error using [&] or [=], or changing my LPCTSTR parameter types to auto. Can anyone see what I am doing wrong?*

'initializing': cannot convert from '<lambda_4ea6e84698d4bd1ce2c6d0d3f1bf1ccc>' to 'CImportTransactions *(__cdecl *)(LPCTSTR,LPCTSTR,LPCTSTR)'

UPDATE 2: I also tried changing my lambda as follows (note the typecast on the return value). (Note that both CImportGasBoyTransactions and CImportOpwTransactions derive from CImportTransactions, so I don't see why the type cast is needed.)

CImportTransactions::ImportModeInfo CImportTransactions::ImportModeTable[] =
{
    { CImportTransactions::ImportMode::GasBoy, _T("GasBoy"), [](LPCTSTR p1, LPCTSTR p2, LPCTSTR p3) { return (CImportTransactions*)new CImportGasBoyTransactions(p1, p2, p3); } },
    { CImportTransactions::ImportMode::Opw, _T("OPW/AFC"), [](LPCTSTR p1, LPCTSTR p2, LPCTSTR p3) { return (CImportTransactions*)new CImportOpwTransactions(p1, p2, p3); } },
};

The result, this seems to eliminate the previous errors. But now I get the following error:

fatal error C1001: An internal error has occurred in the compiler.
(compiler file 'f:\dd\vctools\compiler\utc\src\p2\p2symtab.c', line 7154)
To work around this problem, try simplifying or changing the program near the locations listed above.

Oh boy, aren't I glad I'd give C++ lambdas a try this evening???

Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466
  • Please provide a minimal, compilable piece of code if you want help. – Edward Strange Dec 10 '16 at 04:32
  • it would help if you share ImportModeInfo declaration – Oleg Bogdanov Dec 10 '16 at 04:32
  • Off topic: C++ does the typedef trick for you by default. – user4581301 Dec 10 '16 at 04:34
  • @user4581301: Oh, so it does. Thanks. – Jonathan Wood Dec 10 '16 at 04:35
  • 1
    @JonathanWood *As it is, Intellisense highlights the...* -- Intellisense is not a C++ compiler. What is the actual C++ compiler error that you're getting? – PaulMcKenzie Dec 10 '16 at 05:13
  • The compiler version is in my tags. The error is shown lower down above: `'initializing': cannot convert from '' to 'CImportTransactions *(__cdecl *)(LPCTSTR,LPCTSTR,LPCTSTR)'` Is the problem the return type? See my second update. – Jonathan Wood Dec 10 '16 at 05:16
  • *"Oh boy, aren't I glad I'd give C++ lambdas a try this evening???"* - You may have tried a "hello world" 5-liner first, not a Win32 / Hungarian Notation / MFC / whatever monster... – Christian Hackl Dec 10 '16 at 11:42
  • @ChristianHackl: Thanks for the jab, but I am waaay past Hello-World programs. Thanks for noticing. – Jonathan Wood Dec 10 '16 at 16:14
  • @JonathanWood: Whenever you use X for the first time, you are back to "hello world". At least it's much easier to learn, then... – Christian Hackl Dec 10 '16 at 16:34
  • @ChristianHackl: So you think a Hello-World program is the best way to test out lambdas? I've obviously been doing this much longer than you but moved over to C# for the past decade or two. Please forgive me for trying to incorporate a lambda into a program I've been asked to update. – Jonathan Wood Dec 10 '16 at 16:44
  • 1
    @ChristianHackl: How exactly does Hungarian Notation make lambdas any harder? Or MFC for that matter? And where did you spot any traces of MFC anyway? – IInspectable Dec 11 '16 at 20:15
  • @IInspectable: Hungarian notation (including the MFC-inspired `CName` convention) is typical for Win32/C-style programming, which is related to a completely different paradigma compared to modern functional C++(11) programming. It is typically much easier to learn a new language feature in an idiomatic context -- and without any 3rd-party code. – Christian Hackl Dec 12 '16 at 07:35
  • 1
    @ChristianHackl: MFC, a framework written entirely in C++ is *"typical for Win32/C-style programming"*? Leaving the obvious lapse of reason aside, even if that were the case, how are C++ lambdas conceptually different from any old C-style function pointer? This sounds like you are obsessed with the idea, that you must communicate, how crappy Hungarian Notation, Windows programming, and *"Micro$oft"* in general are, that you'd voice your unfounded opinion at the most remotely related topic (or even a completely unrelated topic, such as this one). – IInspectable Dec 14 '16 at 13:43
  • @IInspectable: Yes, MFC is pretty much C with Classes :) And if you really think lambdas are not conceptually different from function pointers, then I cannot write a meaningful reply to that in a single comment. Besides, I don't have anything against Microsoft, I'm rather happy with most of their products and I have always thought that the joke with the dollar sign was childish. MFC was a child of its time, and I don't blame Microsoft for having created it. So what? If the OP wants to *learn* C++11 features without trying them first in a clean environment, then so be it. – Christian Hackl Dec 14 '16 at 13:52
  • @ChristianHackl: Lambdas in C++ are the same thing, as function pointers in C, where the capture list boils down to passing a hand-crafted context structure. Conceptually, the **exact** same thing. It takes more time than a few years, to clearly distinguish between problems/solutions and programming language syntax. You'll understand, once you're there. – IInspectable Dec 14 '16 at 14:02
  • @IInspectable: So to make a long story short, you consider lambdas syntactic sugar? – Christian Hackl Dec 14 '16 at 14:20
  • @ChristianHackl: You sure know, how to make a short story long. Why don't you start by explaining, how C++ lambdas are inherently different from anything you could possibly implement in C? Your response really resembles that of a five-year-old, who's just been told, that Santa isn't real. – IInspectable Dec 14 '16 at 14:57
  • @IInspectable What, in C++, do you consider to be inherently different from anything you could possibly implement in C? Or any other language typically compiled to native binaries, for that matter? Just to make sure this is not just an argument about the meaning of the word "different". – Christian Hackl Dec 14 '16 at 15:11
  • @ChristianHackl: Lambdas in C++ solve the same problems that function pointers accompanied with contextual state information in C have done so for decades. As such, they can be seen as *"syntactic sugar"*. If you disagree, explain why. – IInspectable Dec 14 '16 at 18:23
  • @IInspectable: A lambda makes the compiler automate a task so that your code does no longer need to implement the mechanism. The **automation** makes the difference. While you could see a lambda as an alternative to the way function pointers turn functions into first-class citizens (or to writing your own functor class), I don't think that's a very useful comparison. C++ itself just solves the same problems that C has solved for decades, but it has arguably brought vast improvements to the table. Now where do *you* draw the line between a purely syntactical decoration and a real difference? – Christian Hackl Dec 15 '16 at 16:55
  • @ChristianHackl: I'm not the one drawing any lines. Remember, it was you that claimed, that it were near-impossible to learn about C++ lambdas in a context that isn't 100% idiomatic C++. I suppose your relative inexperience is to blame. Just keep in mind when offering unsolicited advice, that you may be a lot newer to this than the reader. – IInspectable Dec 16 '16 at 00:15
  • @IInspectable *sigh* Where did I say it was "near-impossible"? You are arguing for the sake of an argument, and your continuous condescending tone makes you look very unprofessional, yourself. I stand by my point, of course: *"I'm trying to use C++ lambdas for the first time"* and the OP's code (which also isn't even remotely close to being an MCVE) do not go together very well. If you don't agree, that's fine. Given the technology background on your profile, it's unlikely we'll see each other again very often here. – Christian Hackl Dec 16 '16 at 08:00
  • @ChristianHackl: So without an MCVE, it's impossible to help someone with an error and the correct syntax for a lambda? Interesting theory. Seems everything is a barrier to you being helpful here. When someone demonstrates why an older style MFC application makes it difficult to understand an error message on a particular line that needs a lambda, I will listen. But until then, it's only so much hooey. – Jonathan Wood Dec 16 '16 at 15:59

2 Answers2

0

This answer says that it's should work.

fatal error C1001

You should report this bug to microsoft of try visual studio 2017, maybe you haven't update visual studio 2015 to update 3?

Community
  • 1
  • 1
Stargateur
  • 24,473
  • 8
  • 65
  • 91
0

Finally solved the problem.

I thought the problem might be that I was returning CImportGasBoyTransactions* and CImportOpwTransactions* but the member was typed as returning CImportTransactions*. I thought this would be okay since those types derive from the declared type. But apparently it isn't.

Performing a typecast on the return value eliminated the error.

CImportTransactions::ImportModeInfo CImportTransactions::ImportModeTable[] =
{
    { CImportTransactions::ImportMode::GasBoy, _T("GasBoy"), [](LPCTSTR p1, LPCTSTR p2, LPCTSTR p3) { return (CImportTransactions*)new CImportGasBoyTransactions(p1, p2, p3); } },
    { CImportTransactions::ImportMode::Opw, _T("OPW/AFC"), [](LPCTSTR p1, LPCTSTR p2, LPCTSTR p3) { return (CImportTransactions*)new CImportOpwTransactions(p1, p2, p3); } },
};

Also played with changing LPCTSTR to auto at the same time. Found about half a dozen variations that caused the compiler to crash with an internal error. Perhaps VS 2015 isn't quite up to handling lambdas yet.

Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466
  • 2
    In c++ always prefer `static_cast` or `dynamic_cast` over c-style cast... – W.F. Dec 10 '16 at 10:45
  • @W.F.: I know that's the newer way to do it but I read the old style works just fine in most cases. Do you see a specific issue with the way I've done it other than just a general preference? – Jonathan Wood Dec 10 '16 at 16:15
  • Well in your particular example c-style cast will work just like `static_cast` would, but in general case c-style cast does more reinterpret casting so it allows things that can cause undefined behaviour. The sooner you get use to c++-style casting the sooner you won't have to do debugging of nasty bugs... – W.F. Dec 10 '16 at 16:42
  • When the compiler encounters a C-style cast, it attempts to interpret it as the following expressions (in this order): A `const_cast`, a `static_cast`, a `static_cast` followed by a `const_cast`, a `reinterpret_cast`, and a `reinterpret_cast` followed by a `const_cast`. Which one of these matches can change when introducing a code change elsewhere. That `const_cast` is particularly vicious. Using explicit casts is a lot safer. – IInspectable Dec 10 '16 at 20:41