Question

while exploring the subject of constexpr/operator"' features of C++11 I stumbled upon this article: http://www.codeproject.com/Articles/447922/Application-of-Cplusplus11-User-Defined-Literals-t

It quotes an example of how would a code providing string-to-binary-number udl look like:

constexpr unsigned long long ToBinary(unsigned long long x, const char* s)
{
    return (!*s ? x : ToBinary(x + x + (*s =='1'? 1 : 0), s+1));
}
constexpr unsigned long long int operator "" _b(const char* s) 
{ return ToBinary(0,s);}

it all works as advertised, but I do not quite like that the global namespace is contaminated with the auxilliary ToBinary function. Instead of trying to mangle the function's name I was attempting to conceive a solution which would have a recursive lambda function embedded within the operator"" body.

Solutions for recursive lambdas in C++ are known and they employ std::function usage. To make that possible within the constexpr operator"" one would need to have the declaration and invocation of the recursive lambda embedded within a single return statement. My attempts to achieve that failed, so I am resorting to SO for help. Is having recursive lambda invoked within constexpr operator"" possible at all? If so, what hints are there?

Thanks,

Était-ce utile?

La solution

As per [expr.const]/2, a lambda-expression is explicitly forbidden to be part of a core constant expression. It can appear in an unevaluated operand of a ternary operator, e.g. p ? 42 : [](){ return 255; }();, if p evaluates to true.

That said, a lambda may also appear in a constexpr function, however, that part may not be evaluated when the function is to be used in a constant expression. Example:

constexpr unsigned long long int operator "" _b(const char* s) 
{
    return *s == '0' || *s == 0 ? 0 : [=]() mutable
    {
        unsigned long long ret = 0;
        for(; *s != 0; ++s)
        {
            ret <<= 1;
            if(*s == '1') ret += 1;
        }
        return ret;
    }();
}

#include <iostream>
int main()
{
    constexpr int c = 0_b;             // fine
    //constexpr int c1 = 1_b;          // error
    std::cout << 1010_b << std::endl;  // fine
}

Of course, this is not very useful; the operator is constexpr to allow parsing strings as binary literals in constant expressions. Therefore, the parts of the operator that do this conversion must be valid (core) constant expressions.

As the signature of the operator is precisely specified, you cannot recur on the operator itself and pass the processed data as an additional argument. You may not use loops in C++11's constexpr either.

Of course, you can use namespaces. This might even be better for the user:

namespace my_literals
{
    constexpr unsigned long long ToBinary(unsigned long long x, const char* s)
    {
        return (!*s ? x : ToBinary(x + x + (*s =='1'? 1 : 0), s+1));
    }
    constexpr unsigned long long int operator "" _b(const char* s) 
    { return ToBinary(0,s);}
}

// user writes:
using my_literals::operator ""_b;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top