Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

which identifiers are available to lambda in constructor initializer list

more to the point, what's wrong with this code:

#include <assert.h>
#include <functional>
using namespace std;

    template< class BaseObjectId >
    class Check
    {
    protected:
        Check( function<bool()> const f ) { assert( f() ); }
    };

    template< int tpMinValue, int tpMaxValue >
    class IntegerSubrange
        : private Check< IntegerSubrange< tpMinValue, tpMaxValue > >
    {
    private:
        int     value_;

    public:
        enum :int { minValue = tpMinValue, maxValue = tpMaxValue };

        static bool rangeContains( int const x )
        {
            return (minValue <= x && x <= maxValue);
        }

        operator int() const
        {
            return value_;
        }

        void operator/=( int const rhs )
        {
            value_ /= rhs;
            assert( rangeContains( value_ ) );
        }

        explicit IntegerSubrange( int const value )
            : Check< IntegerSubrange< tpMinValue, tpMaxValue > >(
                [=]() -> bool { return rangeContains( value ); }
                )
            , value_( value )
        {}
    };

int main() {}

Visual C++ reports a syntax error:

foo.cpp
foo.cpp(41) : error C2059: syntax error : ')'
        foo.cpp(44) : see reference to class template instantiation 'IntegerSubrange' being compiled
foo.cpp(42) : error C2059: syntax error : ','
foo.cpp(43) : error C2334: unexpected token(s) preceding '{'; skipping apparent function body
like image 600
Cheers and hth. - Alf Avatar asked Jul 01 '12 17:07

Cheers and hth. - Alf


1 Answers

To summarize the comments: The questioner's code is valid. Apparently some compilers older than GCC 4.4 or Visual C++ 2011 will reject it, due to those compilers' incomplete support for C++11-style lambdas. But modern compilers (and certainly any compiler that claims to support the new C++11 standard) should handle it just fine.

To answer your question literally: In a ctor-initializer-list, the same identifiers are available (and refer to the same things) as they would refer to if you moved them inside the curly braces of the constructor function itself. In particular, this means that you can do

class C {
    const char *p_ = "foo";
    char c_;
    C(int): p_(__func__) { }      // referring to "__func__"
    C(double): c_(*this->p_) { }  // referring to "this"
};

Here's what the Standard has to say on the subject:

Names in the expression-list or braced-init-list of a mem-initializer are evaluated in the scope of the constructor for which the mem-initializer is specified. ... [Note: Because the mem-initializer are [sic] evaluated in the scope of the constructor, the this pointer can be used in the expression-list of a mem-initializer to refer to the object being initialized. —end note]    (N3337 §12.6.2 #12)

like image 55
Quuxplusone Avatar answered Sep 22 '22 10:09

Quuxplusone