2013-10-03 6 views
1

, исследуя предмет constexpr/оператора "» функций C++ 11, я наткнулся на эту статью: http://www.codeproject.com/Articles/447922/Application-of-Cplusplus11-User-Defined-Literals-tC++ 11 рекурсивная функция лямбда в constexpr оператора «»

Это приводит пример того, как бы, код, обеспечивающий строка-двоичного числа UDL выглядеть:

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

все это работает как рекламируется, но я не совсем так, что глобальное пространство имен загрязненным вспомогательного функции ToBinary Вместо того, чтобы пытаться искажать. имя функции Я пытался задумать решение, которое бы имело рекурсивную лямбда-функцию, встроенную в оператор " тело.

Решения для рекурсивных lambdas на C++ известны, и они используют использование std :: function. Чтобы сделать это возможным в операторе constexpr "", нужно было бы иметь объявление и вызов рекурсивной лямбда, встроенной в один оператор возврата. Мои попытки добиться этого не удались, поэтому я обращаюсь к SO за помощью. Имеет ли рекурсивная лямбда, вызванная внутри оператора constexpr "" вообще? Если да, то какие намеки есть?

Благодаря,

+0

Оператор lambda 'operator()' не помечен 'constexpr', поэтому это невозможно. – Xeo

+0

В C++ 11 выражение lambda не может появляться внутри константного выражения (оно может появляться внутри функции constexpr), поэтому вы не можете использовать функцию constexpr в константном выражении, если эта функция имеет лямбда-выражение в оцененном контекст. – dyp

+0

@Xeo 'constexpr int foo (bool p) {return p? 42: []() {return 255; }(); } 'отлично. – dyp

ответ

3

В соответствии с [expr.const]/2, а лямбда-выражение явно запрещено быть частью константного выражения основной. Он может отображаться в неоцененном операнде тройного оператора, например. p ? 42 : [](){ return 255; }();, если p - true.

При этом в функции constexpr также может появляться лямбда, однако эта часть не может быть оценена, когда функция должна использоваться в постоянном выражении. Пример:

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 
} 

Конечно, это не очень полезно; оператор constexpr до разрешает разбор строк в виде двоичных литералов в постоянных выражениях. Поэтому части оператора, которые делают это преобразование, должны быть действительными (ядро) постоянными выражениями.

Поскольку сигнатура оператора точно указана, вы не можете повторить сам оператор и передать обработанные данные в качестве дополнительного аргумента. Вы также не можете использовать циклы в C++ 11's constexpr.

Конечно, вы можете использовать пространства имен. Это может быть даже лучше для пользователя:

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; 
+0

Вау, это объяснение, которое просто оставило меня безмолвным. Краткая и полная, даже с идеями альтернативных путей. Большое спасибо! –

 Смежные вопросы

  • Нет связанных вопросов^_^