Altimor
Altimor

Reputation: 43

Discrepancy with lambda conversion constructor in GCC/MSVC

Which one, if not both, is breaking spec? Tried with MSVC on both MSVC 2013 and MSVC Nov 2013 CTP, GCC was MinGW x64 4.9.1 with -std=c++11.

template<typename ret_type>
class memoizer
{
    using func_type = ret_type(*)(const int);
    const func_type func;

    std::map<int, ret_type> cache;

public:
    memoizer(func_type func) : func(func)
    {
    }

    ret_type operator [](const int n)
    {
        const auto it = cache.find(n);
        if(it != cache.end())
            return it->second;

        return cache[n] = func(n);
    }
};

//works in GCC but not MSVC
//error C2065: 'fib' : undeclared identifier
memoizer<int64_t> fib([](const int n)
{
    return n < 2 ? n : fib[n - 1] + fib[n - 2];
});

//works in MSVC but not GCC
//error: conversion from '<lambda(int)>' to non-scalar type 'memoizer<long long int>' requested
memoizer<int64_t> fib = [](const int n)
{
    return n < 2 ? n : fib[n - 1] + fib[n - 2];
};

This seems to stem from the way they're handling lambda types differently, and when they consider a variable to be defined.

Upvotes: 4

Views: 289

Answers (1)

user743382
user743382

Reputation:

GCC is right.

For your first form:

A variable is considered declared at the end of its declarator, which is before its initialiser. This is why the this form is valid. The famous example is int i = i;, which is syntactically valid and initialises i with its own (indeterminate) value.

For your second form:

Your initialisation with = fails because you have two user-defined conversions. (The lambda type's conversion operator is considered user-defined.) It is analogous to

struct A { };
struct B { B(A) { } };
struct C { C(B) { } };
A a;
C c1(a); // okay
C c2 = a; // error

Upvotes: 5

Related Questions